From 028c6d12fa940b6bec1b7ea828e2d2b8c202d4a2 Mon Sep 17 00:00:00 2001 From: ceedii Date: Sat, 28 Jan 2023 03:27:50 +0000 Subject: [PATCH 01/38] Code cleaning, remove libsodium from libetchash and libubqhash (redundant) --- src/Native/libetchash/libetchash.vcxproj | 18 +- .../windows/include/libsodium/sodium.h | 68 ------- .../windows/include/libsodium/sodium/core.h | 19 -- .../libsodium/sodium/crypto_aead_aes256gcm.h | 145 --------------- .../sodium/crypto_aead_chacha20poly1305.h | 162 ----------------- .../sodium/crypto_aead_xchacha20poly1305.h | 91 ---------- .../include/libsodium/sodium/crypto_auth.h | 44 ----- .../libsodium/sodium/crypto_auth_hmacsha256.h | 68 ------- .../libsodium/sodium/crypto_auth_hmacsha512.h | 67 ------- .../sodium/crypto_auth_hmacsha512256.h | 62 ------- .../include/libsodium/sodium/crypto_box.h | 169 ------------------ .../crypto_box_curve25519xchacha20poly1305.h | 153 ---------------- .../crypto_box_curve25519xsalsa20poly1305.h | 100 ----------- .../libsodium/sodium/crypto_core_hchacha20.h | 35 ---- .../libsodium/sodium/crypto_core_hsalsa20.h | 35 ---- .../libsodium/sodium/crypto_core_salsa20.h | 35 ---- .../libsodium/sodium/crypto_core_salsa2012.h | 35 ---- .../libsodium/sodium/crypto_core_salsa208.h | 35 ---- .../libsodium/sodium/crypto_generichash.h | 75 -------- .../sodium/crypto_generichash_blake2b.h | 117 ------------ .../include/libsodium/sodium/crypto_hash.h | 40 ----- .../libsodium/sodium/crypto_hash_sha256.h | 57 ------ .../libsodium/sodium/crypto_hash_sha512.h | 57 ------ .../include/libsodium/sodium/crypto_kdf.h | 51 ------ .../libsodium/sodium/crypto_kdf_blake2b.h | 42 ----- .../include/libsodium/sodium/crypto_kx.h | 64 ------- .../libsodium/sodium/crypto_onetimeauth.h | 62 ------- .../sodium/crypto_onetimeauth_poly1305.h | 67 ------- .../include/libsodium/sodium/crypto_pwhash.h | 134 -------------- .../libsodium/sodium/crypto_pwhash_argon2i.h | 116 ------------ .../libsodium/sodium/crypto_pwhash_argon2id.h | 116 ------------ .../crypto_pwhash_scryptsalsa208sha256.h | 112 ------------ .../libsodium/sodium/crypto_scalarmult.h | 37 ---- .../sodium/crypto_scalarmult_curve25519.h | 32 ---- .../libsodium/sodium/crypto_secretbox.h | 87 --------- .../crypto_secretbox_xchacha20poly1305.h | 62 ------- .../crypto_secretbox_xsalsa20poly1305.h | 58 ------ .../libsodium/sodium/crypto_shorthash.h | 39 ---- .../sodium/crypto_shorthash_siphash24.h | 48 ----- .../include/libsodium/sodium/crypto_sign.h | 99 ---------- .../libsodium/sodium/crypto_sign_ed25519.h | 110 ------------ .../crypto_sign_edwards25519sha512batch.h | 54 ------ .../include/libsodium/sodium/crypto_stream.h | 52 ------ .../sodium/crypto_stream_aes128ctr.h | 65 ------- .../libsodium/sodium/crypto_stream_chacha20.h | 88 --------- .../libsodium/sodium/crypto_stream_salsa20.h | 53 ------ .../sodium/crypto_stream_salsa2012.h | 46 ----- .../libsodium/sodium/crypto_stream_salsa208.h | 46 ----- .../sodium/crypto_stream_xchacha20.h | 53 ------ .../libsodium/sodium/crypto_stream_xsalsa20.h | 53 ------ .../libsodium/sodium/crypto_verify_16.h | 23 --- .../libsodium/sodium/crypto_verify_32.h | 23 --- .../libsodium/sodium/crypto_verify_64.h | 23 --- .../windows/include/libsodium/sodium/export.h | 44 ----- .../include/libsodium/sodium/randombytes.h | 66 ------- .../sodium/randombytes_salsa20_random.h | 19 -- .../libsodium/sodium/randombytes_sysrandom.h | 19 -- .../include/libsodium/sodium/runtime.h | 46 ----- .../windows/include/libsodium/sodium/utils.h | 131 -------------- .../include/libsodium/sodium/version.h | 33 ---- .../libetchash/windows/lib/x64/libsodium.lib | Bin 1885178 -> 0 bytes .../libetchash/windows/lib/x86/libsodium.lib | Bin 2044152 -> 0 bytes src/Native/libubqhash/libubqhash.vcxproj | 16 +- .../windows/include/libsodium/sodium.h | 68 ------- .../windows/include/libsodium/sodium/core.h | 19 -- .../libsodium/sodium/crypto_aead_aes256gcm.h | 145 --------------- .../sodium/crypto_aead_chacha20poly1305.h | 162 ----------------- .../sodium/crypto_aead_xchacha20poly1305.h | 91 ---------- .../include/libsodium/sodium/crypto_auth.h | 44 ----- .../libsodium/sodium/crypto_auth_hmacsha256.h | 68 ------- .../libsodium/sodium/crypto_auth_hmacsha512.h | 67 ------- .../sodium/crypto_auth_hmacsha512256.h | 62 ------- .../include/libsodium/sodium/crypto_box.h | 169 ------------------ .../crypto_box_curve25519xchacha20poly1305.h | 153 ---------------- .../crypto_box_curve25519xsalsa20poly1305.h | 100 ----------- .../libsodium/sodium/crypto_core_hchacha20.h | 35 ---- .../libsodium/sodium/crypto_core_hsalsa20.h | 35 ---- .../libsodium/sodium/crypto_core_salsa20.h | 35 ---- .../libsodium/sodium/crypto_core_salsa2012.h | 35 ---- .../libsodium/sodium/crypto_core_salsa208.h | 35 ---- .../libsodium/sodium/crypto_generichash.h | 75 -------- .../sodium/crypto_generichash_blake2b.h | 117 ------------ .../include/libsodium/sodium/crypto_hash.h | 40 ----- .../libsodium/sodium/crypto_hash_sha256.h | 57 ------ .../libsodium/sodium/crypto_hash_sha512.h | 57 ------ .../include/libsodium/sodium/crypto_kdf.h | 51 ------ .../libsodium/sodium/crypto_kdf_blake2b.h | 42 ----- .../include/libsodium/sodium/crypto_kx.h | 64 ------- .../libsodium/sodium/crypto_onetimeauth.h | 62 ------- .../sodium/crypto_onetimeauth_poly1305.h | 67 ------- .../include/libsodium/sodium/crypto_pwhash.h | 134 -------------- .../libsodium/sodium/crypto_pwhash_argon2i.h | 116 ------------ .../libsodium/sodium/crypto_pwhash_argon2id.h | 116 ------------ .../crypto_pwhash_scryptsalsa208sha256.h | 112 ------------ .../libsodium/sodium/crypto_scalarmult.h | 37 ---- .../sodium/crypto_scalarmult_curve25519.h | 32 ---- .../libsodium/sodium/crypto_secretbox.h | 87 --------- .../crypto_secretbox_xchacha20poly1305.h | 62 ------- .../crypto_secretbox_xsalsa20poly1305.h | 58 ------ .../libsodium/sodium/crypto_shorthash.h | 39 ---- .../sodium/crypto_shorthash_siphash24.h | 48 ----- .../include/libsodium/sodium/crypto_sign.h | 99 ---------- .../libsodium/sodium/crypto_sign_ed25519.h | 110 ------------ .../crypto_sign_edwards25519sha512batch.h | 54 ------ .../include/libsodium/sodium/crypto_stream.h | 52 ------ .../sodium/crypto_stream_aes128ctr.h | 65 ------- .../libsodium/sodium/crypto_stream_chacha20.h | 88 --------- .../libsodium/sodium/crypto_stream_salsa20.h | 53 ------ .../sodium/crypto_stream_salsa2012.h | 46 ----- .../libsodium/sodium/crypto_stream_salsa208.h | 46 ----- .../sodium/crypto_stream_xchacha20.h | 53 ------ .../libsodium/sodium/crypto_stream_xsalsa20.h | 53 ------ .../libsodium/sodium/crypto_verify_16.h | 23 --- .../libsodium/sodium/crypto_verify_32.h | 23 --- .../libsodium/sodium/crypto_verify_64.h | 23 --- .../windows/include/libsodium/sodium/export.h | 44 ----- .../include/libsodium/sodium/randombytes.h | 66 ------- .../sodium/randombytes_salsa20_random.h | 19 -- .../libsodium/sodium/randombytes_sysrandom.h | 19 -- .../include/libsodium/sodium/runtime.h | 46 ----- .../windows/include/libsodium/sodium/utils.h | 131 -------------- .../include/libsodium/sodium/version.h | 33 ---- .../libubqhash/windows/lib/x64/libsodium.lib | Bin 1885178 -> 0 bytes .../libubqhash/windows/lib/x86/libsodium.lib | Bin 2044152 -> 0 bytes 124 files changed, 17 insertions(+), 7901 deletions(-) delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/core.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_box.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hchacha20.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa20.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa2012.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa208.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha256.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha512.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_kx.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_ed25519.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_chacha20.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa20.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa208.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_16.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_32.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_64.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/export.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/randombytes.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/randombytes_salsa20_random.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/randombytes_sysrandom.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/runtime.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/utils.h delete mode 100644 src/Native/libetchash/windows/include/libsodium/sodium/version.h delete mode 100644 src/Native/libetchash/windows/lib/x64/libsodium.lib delete mode 100644 src/Native/libetchash/windows/lib/x86/libsodium.lib delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/core.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hchacha20.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa20.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa2012.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa208.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha256.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha512.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kx.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_ed25519.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_chacha20.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa20.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa208.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_16.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_32.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_64.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/export.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/randombytes.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_salsa20_random.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_sysrandom.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/runtime.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/utils.h delete mode 100644 src/Native/libubqhash/windows/include/libsodium/sodium/version.h delete mode 100644 src/Native/libubqhash/windows/lib/x64/libsodium.lib delete mode 100644 src/Native/libubqhash/windows/lib/x86/libsodium.lib diff --git a/src/Native/libetchash/libetchash.vcxproj b/src/Native/libetchash/libetchash.vcxproj index 6ad5c0091..160fd6567 100644 --- a/src/Native/libetchash/libetchash.vcxproj +++ b/src/Native/libetchash/libetchash.vcxproj @@ -73,22 +73,22 @@ true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libethhash\windows\lib\x64;$(LibraryPath) false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) @@ -105,7 +105,7 @@ Windows true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) @@ -122,7 +122,7 @@ Windows true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) @@ -143,7 +143,7 @@ true true true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) @@ -164,7 +164,7 @@ true true true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) diff --git a/src/Native/libetchash/windows/include/libsodium/sodium.h b/src/Native/libetchash/windows/include/libsodium/sodium.h deleted file mode 100644 index 1f79e87bf..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium.h +++ /dev/null @@ -1,68 +0,0 @@ - -#ifndef sodium_H -#define sodium_H - -#include "sodium/version.h" - -#include "sodium/core.h" -#include "sodium/crypto_aead_aes256gcm.h" -#include "sodium/crypto_aead_chacha20poly1305.h" -#include "sodium/crypto_aead_xchacha20poly1305.h" -#include "sodium/crypto_auth.h" -#include "sodium/crypto_auth_hmacsha256.h" -#include "sodium/crypto_auth_hmacsha512.h" -#include "sodium/crypto_auth_hmacsha512256.h" -#include "sodium/crypto_box.h" -#include "sodium/crypto_box_curve25519xsalsa20poly1305.h" -#include "sodium/crypto_core_hsalsa20.h" -#include "sodium/crypto_core_hchacha20.h" -#include "sodium/crypto_core_salsa20.h" -#include "sodium/crypto_core_salsa2012.h" -#include "sodium/crypto_core_salsa208.h" -#include "sodium/crypto_generichash.h" -#include "sodium/crypto_generichash_blake2b.h" -#include "sodium/crypto_hash.h" -#include "sodium/crypto_hash_sha256.h" -#include "sodium/crypto_hash_sha512.h" -#include "sodium/crypto_kdf.h" -#include "sodium/crypto_kdf_blake2b.h" -#include "sodium/crypto_kx.h" -#include "sodium/crypto_onetimeauth.h" -#include "sodium/crypto_onetimeauth_poly1305.h" -#include "sodium/crypto_pwhash.h" -#include "sodium/crypto_pwhash_argon2i.h" -#include "sodium/crypto_scalarmult.h" -#include "sodium/crypto_scalarmult_curve25519.h" -#include "sodium/crypto_secretbox.h" -#include "sodium/crypto_secretbox_xsalsa20poly1305.h" -#include "sodium/crypto_shorthash.h" -#include "sodium/crypto_shorthash_siphash24.h" -#include "sodium/crypto_sign.h" -#include "sodium/crypto_sign_ed25519.h" -#include "sodium/crypto_stream.h" -#include "sodium/crypto_stream_chacha20.h" -#include "sodium/crypto_stream_salsa20.h" -#include "sodium/crypto_stream_xsalsa20.h" -#include "sodium/crypto_verify_16.h" -#include "sodium/crypto_verify_32.h" -#include "sodium/crypto_verify_64.h" -#include "sodium/randombytes.h" -#ifdef __native_client__ -# include "sodium/randombytes_nativeclient.h" -#endif -#include "sodium/randombytes_salsa20_random.h" -#include "sodium/randombytes_sysrandom.h" -#include "sodium/runtime.h" -#include "sodium/utils.h" - -#ifndef SODIUM_LIBRARY_MINIMAL -# include "sodium/crypto_box_curve25519xchacha20poly1305.h" -# include "sodium/crypto_secretbox_xchacha20poly1305.h" -# include "sodium/crypto_pwhash_scryptsalsa208sha256.h" -# include "sodium/crypto_stream_aes128ctr.h" -# include "sodium/crypto_stream_salsa2012.h" -# include "sodium/crypto_stream_salsa208.h" -# include "sodium/crypto_stream_xchacha20.h" -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/core.h b/src/Native/libetchash/windows/include/libsodium/sodium/core.h deleted file mode 100644 index 3ca447628..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/core.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef sodium_core_H -#define sodium_core_H - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -int sodium_init(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h deleted file mode 100644 index 972df54f6..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h +++ /dev/null @@ -1,145 +0,0 @@ -#ifndef crypto_aead_aes256gcm_H -#define crypto_aead_aes256gcm_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -SODIUM_EXPORT -int crypto_aead_aes256gcm_is_available(void); - -#define crypto_aead_aes256gcm_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_keybytes(void); - -#define crypto_aead_aes256gcm_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_nsecbytes(void); - -#define crypto_aead_aes256gcm_NPUBBYTES 12U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_npubbytes(void); - -#define crypto_aead_aes256gcm_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_abytes(void); - -typedef CRYPTO_ALIGN(16) unsigned char crypto_aead_aes256gcm_state[512]; - -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_statebytes(void); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* -- Precomputation interface -- */ - -SODIUM_EXPORT -int crypto_aead_aes256gcm_beforenm(crypto_aead_aes256gcm_state *ctx_, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_afternm(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_afternm(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_detached_afternm(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_detached_afternm(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_aes256gcm_keygen(unsigned char k[crypto_aead_aes256gcm_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h deleted file mode 100644 index 0bbc68859..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef crypto_aead_chacha20poly1305_H -#define crypto_aead_chacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -/* -- IETF ChaCha20-Poly1305 construction with a 96-bit nonce and a 32-bit internal counter -- */ - -#define crypto_aead_chacha20poly1305_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_keybytes(void); - -#define crypto_aead_chacha20poly1305_ietf_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_nsecbytes(void); - -#define crypto_aead_chacha20poly1305_ietf_NPUBBYTES 12U - -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_npubbytes(void); - -#define crypto_aead_chacha20poly1305_ietf_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_abytes(void); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_chacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_chacha20poly1305_ietf_KEYBYTES]); - -/* -- Original ChaCha20-Poly1305 construction with a 64-bit nonce and a 64-bit internal counter -- */ - -#define crypto_aead_chacha20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_keybytes(void); - -#define crypto_aead_chacha20poly1305_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_nsecbytes(void); - -#define crypto_aead_chacha20poly1305_NPUBBYTES 8U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_npubbytes(void); - -#define crypto_aead_chacha20poly1305_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_abytes(void); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_chacha20poly1305_keygen(unsigned char k[crypto_aead_chacha20poly1305_KEYBYTES]); - -/* Aliases */ - -#define crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_ietf_KEYBYTES -#define crypto_aead_chacha20poly1305_IETF_NSECBYTES crypto_aead_chacha20poly1305_ietf_NSECBYTES -#define crypto_aead_chacha20poly1305_IETF_NPUBBYTES crypto_aead_chacha20poly1305_ietf_NPUBBYTES -#define crypto_aead_chacha20poly1305_IETF_ABYTES crypto_aead_chacha20poly1305_ietf_ABYTES - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h deleted file mode 100644 index f863ce88c..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef crypto_aead_xchacha20poly1305_H -#define crypto_aead_xchacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_aead_xchacha20poly1305_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_keybytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_nsecbytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_NPUBBYTES 24U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_npubbytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_abytes(void); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_xchacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES]); - -/* Aliases */ - -#define crypto_aead_xchacha20poly1305_IETF_KEYBYTES crypto_aead_xchacha20poly1305_ietf_KEYBYTES -#define crypto_aead_xchacha20poly1305_IETF_NSECBYTES crypto_aead_xchacha20poly1305_ietf_NSECBYTES -#define crypto_aead_xchacha20poly1305_IETF_NPUBBYTES crypto_aead_xchacha20poly1305_ietf_NPUBBYTES -#define crypto_aead_xchacha20poly1305_IETF_ABYTES crypto_aead_xchacha20poly1305_ietf_ABYTES - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth.h deleted file mode 100644 index 7174e7bce..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef crypto_auth_H -#define crypto_auth_H - -#include - -#include "crypto_auth_hmacsha512256.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES -SODIUM_EXPORT -size_t crypto_auth_bytes(void); - -#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES -SODIUM_EXPORT -size_t crypto_auth_keybytes(void); - -#define crypto_auth_PRIMITIVE "hmacsha512256" -SODIUM_EXPORT -const char *crypto_auth_primitive(void); - -SODIUM_EXPORT -int crypto_auth(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_verify(const unsigned char *h, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_auth_keygen(unsigned char k[crypto_auth_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h deleted file mode 100644 index deec5266e..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef crypto_auth_hmacsha256_H -#define crypto_auth_hmacsha256_H - -#include -#include "crypto_hash_sha256.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha256_BYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_bytes(void); - -#define crypto_auth_hmacsha256_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha256(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* ------------------------------------------------------------------------- */ - -typedef struct crypto_auth_hmacsha256_state { - crypto_hash_sha256_state ictx; - crypto_hash_sha256_state octx; -} crypto_auth_hmacsha256_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_init(crypto_auth_hmacsha256_state *state, - const unsigned char *key, - size_t keylen); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_update(crypto_auth_hmacsha256_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_final(crypto_auth_hmacsha256_state *state, - unsigned char *out); - - -SODIUM_EXPORT -void crypto_auth_hmacsha256_keygen(unsigned char k[crypto_auth_hmacsha256_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h deleted file mode 100644 index 77a55fbc0..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef crypto_auth_hmacsha512_H -#define crypto_auth_hmacsha512_H - -#include -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha512_BYTES 64U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_bytes(void); - -#define crypto_auth_hmacsha512_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* ------------------------------------------------------------------------- */ - -typedef struct crypto_auth_hmacsha512_state { - crypto_hash_sha512_state ictx; - crypto_hash_sha512_state octx; -} crypto_auth_hmacsha512_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_init(crypto_auth_hmacsha512_state *state, - const unsigned char *key, - size_t keylen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_update(crypto_auth_hmacsha512_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_final(crypto_auth_hmacsha512_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_auth_hmacsha512_keygen(unsigned char k[crypto_auth_hmacsha512_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h deleted file mode 100644 index 4842f3deb..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef crypto_auth_hmacsha512256_H -#define crypto_auth_hmacsha512256_H - -#include -#include "crypto_auth_hmacsha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha512256_BYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_bytes(void); - -#define crypto_auth_hmacsha512256_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256(unsigned char *out, const unsigned char *in, - unsigned long long inlen,const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* ------------------------------------------------------------------------- */ - -typedef crypto_auth_hmacsha512_state crypto_auth_hmacsha512256_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_init(crypto_auth_hmacsha512256_state *state, - const unsigned char *key, - size_t keylen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_update(crypto_auth_hmacsha512256_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_final(crypto_auth_hmacsha512256_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_auth_hmacsha512256_keygen(unsigned char k[crypto_auth_hmacsha512256_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box.h deleted file mode 100644 index 614cd1e0a..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef crypto_box_H -#define crypto_box_H - -/* - * THREAD SAFETY: crypto_box_keypair() is thread-safe, - * provided that sodium_init() was called before. - * - * Other functions are always thread-safe. - */ - -#include - -#include "crypto_box_curve25519xsalsa20poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_SEEDBYTES crypto_box_curve25519xsalsa20poly1305_SEEDBYTES -SODIUM_EXPORT -size_t crypto_box_seedbytes(void); - -#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES -SODIUM_EXPORT -size_t crypto_box_publickeybytes(void); - -#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES -SODIUM_EXPORT -size_t crypto_box_secretkeybytes(void); - -#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES -SODIUM_EXPORT -size_t crypto_box_noncebytes(void); - -#define crypto_box_MACBYTES crypto_box_curve25519xsalsa20poly1305_MACBYTES -SODIUM_EXPORT -size_t crypto_box_macbytes(void); - -#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" -SODIUM_EXPORT -const char *crypto_box_primitive(void); - -SODIUM_EXPORT -int crypto_box_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_box_keypair(unsigned char *pk, unsigned char *sk); - -SODIUM_EXPORT -int crypto_box_easy(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_open_easy(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_detached(unsigned char *c, unsigned char *mac, - const unsigned char *m, unsigned long long mlen, - const unsigned char *n, const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_open_detached(unsigned char *m, const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -/* -- Precomputation interface -- */ - -#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES -SODIUM_EXPORT -size_t crypto_box_beforenmbytes(void); - -SODIUM_EXPORT -int crypto_box_beforenm(unsigned char *k, const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_easy_afternm(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_open_easy_afternm(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_detached_afternm(unsigned char *c, unsigned char *mac, - const unsigned char *m, unsigned long long mlen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_open_detached_afternm(unsigned char *m, const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* -- Ephemeral SK interface -- */ - -#define crypto_box_SEALBYTES (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_sealbytes(void); - -SODIUM_EXPORT -int crypto_box_seal(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *pk); - -SODIUM_EXPORT -int crypto_box_seal_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES -SODIUM_EXPORT -size_t crypto_box_zerobytes(void); - -#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES -SODIUM_EXPORT -size_t crypto_box_boxzerobytes(void); - -SODIUM_EXPORT -int crypto_box(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_afternm(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_open_afternm(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h deleted file mode 100644 index b781cc6e8..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h +++ /dev/null @@ -1,153 +0,0 @@ - -#ifndef crypto_box_curve25519xchacha20poly1305_H -#define crypto_box_curve25519xchacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_curve25519xchacha20poly1305_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_seedbytes(void); - -#define crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_publickeybytes(void); - -#define crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_secretkeybytes(void); - -#define crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_beforenmbytes(void); - -#define crypto_box_curve25519xchacha20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_noncebytes(void); - -#define crypto_box_curve25519xchacha20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_macbytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seed_keypair(unsigned char *pk, - unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_keypair(unsigned char *pk, - unsigned char *sk); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_easy(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_easy(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_detached(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -/* -- Precomputation interface -- */ - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_beforenm(unsigned char *k, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_easy_afternm(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_easy_afternm(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_detached_afternm(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_detached_afternm(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* -- Ephemeral SK interface -- */ - -#define crypto_box_curve25519xchacha20poly1305_SEALBYTES \ - (crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES + \ - crypto_box_curve25519xchacha20poly1305_MACBYTES) - -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_sealbytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seal(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seal_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h deleted file mode 100644 index 9b5a39c3f..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef crypto_box_curve25519xsalsa20poly1305_H -#define crypto_box_curve25519xsalsa20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_curve25519xsalsa20poly1305_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_seedbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_publickeybytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_secretkeybytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_beforenmbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_noncebytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_macbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_boxzerobytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES \ - (crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES + \ - crypto_box_curve25519xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_zerobytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_seed_keypair(unsigned char *pk, - unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_keypair(unsigned char *pk, - unsigned char *sk); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_beforenm(unsigned char *k, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_afternm(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_open_afternm(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hchacha20.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hchacha20.h deleted file mode 100644 index 05e5670c1..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hchacha20.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_hchacha20_H -#define crypto_core_hchacha20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_hchacha20_OUTPUTBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hchacha20_outputbytes(void); - -#define crypto_core_hchacha20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hchacha20_inputbytes(void); - -#define crypto_core_hchacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hchacha20_keybytes(void); - -#define crypto_core_hchacha20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hchacha20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_hchacha20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h deleted file mode 100644 index 82e475b8f..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_hsalsa20_H -#define crypto_core_hsalsa20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_hsalsa20_OUTPUTBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_outputbytes(void); - -#define crypto_core_hsalsa20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_inputbytes(void); - -#define crypto_core_hsalsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_keybytes(void); - -#define crypto_core_hsalsa20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_hsalsa20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa20.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa20.h deleted file mode 100644 index 160cc56d2..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa20.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_salsa20_H -#define crypto_core_salsa20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa20_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa20_outputbytes(void); - -#define crypto_core_salsa20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa20_inputbytes(void); - -#define crypto_core_salsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa20_keybytes(void); - -#define crypto_core_salsa20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa2012.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa2012.h deleted file mode 100644 index bdd5f9fdb..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa2012.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_salsa2012_H -#define crypto_core_salsa2012_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa2012_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa2012_outputbytes(void); - -#define crypto_core_salsa2012_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa2012_inputbytes(void); - -#define crypto_core_salsa2012_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa2012_keybytes(void); - -#define crypto_core_salsa2012_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa2012_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa2012(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa208.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa208.h deleted file mode 100644 index 3c13efa4e..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_core_salsa208.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_salsa208_H -#define crypto_core_salsa208_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa208_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa208_outputbytes(void); - -#define crypto_core_salsa208_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa208_inputbytes(void); - -#define crypto_core_salsa208_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa208_keybytes(void); - -#define crypto_core_salsa208_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa208_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa208(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash.h deleted file mode 100644 index 2398fb9db..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef crypto_generichash_H -#define crypto_generichash_H - -#include - -#include "crypto_generichash_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_generichash_BYTES_MIN crypto_generichash_blake2b_BYTES_MIN -SODIUM_EXPORT -size_t crypto_generichash_bytes_min(void); - -#define crypto_generichash_BYTES_MAX crypto_generichash_blake2b_BYTES_MAX -SODIUM_EXPORT -size_t crypto_generichash_bytes_max(void); - -#define crypto_generichash_BYTES crypto_generichash_blake2b_BYTES -SODIUM_EXPORT -size_t crypto_generichash_bytes(void); - -#define crypto_generichash_KEYBYTES_MIN crypto_generichash_blake2b_KEYBYTES_MIN -SODIUM_EXPORT -size_t crypto_generichash_keybytes_min(void); - -#define crypto_generichash_KEYBYTES_MAX crypto_generichash_blake2b_KEYBYTES_MAX -SODIUM_EXPORT -size_t crypto_generichash_keybytes_max(void); - -#define crypto_generichash_KEYBYTES crypto_generichash_blake2b_KEYBYTES -SODIUM_EXPORT -size_t crypto_generichash_keybytes(void); - -#define crypto_generichash_PRIMITIVE "blake2b" -SODIUM_EXPORT -const char *crypto_generichash_primitive(void); - -typedef crypto_generichash_blake2b_state crypto_generichash_state; - -SODIUM_EXPORT -size_t crypto_generichash_statebytes(void); - -SODIUM_EXPORT -int crypto_generichash(unsigned char *out, size_t outlen, - const unsigned char *in, unsigned long long inlen, - const unsigned char *key, size_t keylen); - -SODIUM_EXPORT -int crypto_generichash_init(crypto_generichash_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen); - -SODIUM_EXPORT -int crypto_generichash_update(crypto_generichash_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_generichash_final(crypto_generichash_state *state, - unsigned char *out, const size_t outlen); - -SODIUM_EXPORT -void crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h deleted file mode 100644 index 9326a04ad..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef crypto_generichash_blake2b_H -#define crypto_generichash_blake2b_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack(1) -#else -# pragma pack(push, 1) -#endif - -typedef struct CRYPTO_ALIGN(64) crypto_generichash_blake2b_state { - uint64_t h[8]; - uint64_t t[2]; - uint64_t f[2]; - uint8_t buf[2 * 128]; - size_t buflen; - uint8_t last_node; -} crypto_generichash_blake2b_state; - -#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack() -#else -# pragma pack(pop) -#endif - -#define crypto_generichash_blake2b_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes_min(void); - -#define crypto_generichash_blake2b_BYTES_MAX 64U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes_max(void); - -#define crypto_generichash_blake2b_BYTES 32U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes(void); - -#define crypto_generichash_blake2b_KEYBYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes_min(void); - -#define crypto_generichash_blake2b_KEYBYTES_MAX 64U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes_max(void); - -#define crypto_generichash_blake2b_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes(void); - -#define crypto_generichash_blake2b_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_saltbytes(void); - -#define crypto_generichash_blake2b_PERSONALBYTES 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_personalbytes(void); - -SODIUM_EXPORT -size_t crypto_generichash_blake2b_statebytes(void); - -SODIUM_EXPORT -int crypto_generichash_blake2b(unsigned char *out, size_t outlen, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *key, size_t keylen); - -SODIUM_EXPORT -int crypto_generichash_blake2b_salt_personal(unsigned char *out, size_t outlen, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *key, - size_t keylen, - const unsigned char *salt, - const unsigned char *personal); - -SODIUM_EXPORT -int crypto_generichash_blake2b_init(crypto_generichash_blake2b_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen); - -SODIUM_EXPORT -int crypto_generichash_blake2b_init_salt_personal(crypto_generichash_blake2b_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen, - const unsigned char *salt, - const unsigned char *personal); - -SODIUM_EXPORT -int crypto_generichash_blake2b_update(crypto_generichash_blake2b_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_generichash_blake2b_final(crypto_generichash_blake2b_state *state, - unsigned char *out, - const size_t outlen); - -SODIUM_EXPORT -void crypto_generichash_blake2b_keygen(unsigned char k[crypto_generichash_blake2b_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash.h deleted file mode 100644 index 302ed5c5e..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef crypto_hash_H -#define crypto_hash_H - -/* - * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA512, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include - -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_hash_BYTES crypto_hash_sha512_BYTES -SODIUM_EXPORT -size_t crypto_hash_bytes(void); - -SODIUM_EXPORT -int crypto_hash(unsigned char *out, const unsigned char *in, - unsigned long long inlen); - -#define crypto_hash_PRIMITIVE "sha512" -SODIUM_EXPORT -const char *crypto_hash_primitive(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha256.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha256.h deleted file mode 100644 index f64d16e0e..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha256.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef crypto_hash_sha256_H -#define crypto_hash_sha256_H - -/* - * WARNING: Unless you absolutely need to use SHA256 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA256, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_hash_sha256_state { - uint32_t state[8]; - uint64_t count; - uint8_t buf[64]; -} crypto_hash_sha256_state; - -SODIUM_EXPORT -size_t crypto_hash_sha256_statebytes(void); - -#define crypto_hash_sha256_BYTES 32U -SODIUM_EXPORT -size_t crypto_hash_sha256_bytes(void); - -SODIUM_EXPORT -int crypto_hash_sha256(unsigned char *out, const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha256_init(crypto_hash_sha256_state *state); - -SODIUM_EXPORT -int crypto_hash_sha256_update(crypto_hash_sha256_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha256_final(crypto_hash_sha256_state *state, - unsigned char *out); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha512.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha512.h deleted file mode 100644 index 6b0330f14..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_hash_sha512.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef crypto_hash_sha512_H -#define crypto_hash_sha512_H - -/* - * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA512, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_hash_sha512_state { - uint64_t state[8]; - uint64_t count[2]; - uint8_t buf[128]; -} crypto_hash_sha512_state; - -SODIUM_EXPORT -size_t crypto_hash_sha512_statebytes(void); - -#define crypto_hash_sha512_BYTES 64U -SODIUM_EXPORT -size_t crypto_hash_sha512_bytes(void); - -SODIUM_EXPORT -int crypto_hash_sha512(unsigned char *out, const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha512_init(crypto_hash_sha512_state *state); - -SODIUM_EXPORT -int crypto_hash_sha512_update(crypto_hash_sha512_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha512_final(crypto_hash_sha512_state *state, - unsigned char *out); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf.h deleted file mode 100644 index 52e496a74..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef crypto_kdf_H -#define crypto_kdf_H - -#include -#include - -#include "crypto_kdf_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kdf_BYTES_MIN crypto_kdf_blake2b_BYTES_MIN -SODIUM_EXPORT -size_t crypto_kdf_bytes_min(void); - -#define crypto_kdf_BYTES_MAX crypto_kdf_blake2b_BYTES_MAX -SODIUM_EXPORT -size_t crypto_kdf_bytes_max(void); - -#define crypto_kdf_CONTEXTBYTES crypto_kdf_blake2b_CONTEXTBYTES -SODIUM_EXPORT -size_t crypto_kdf_contextbytes(void); - -#define crypto_kdf_KEYBYTES crypto_kdf_blake2b_KEYBYTES -SODIUM_EXPORT -size_t crypto_kdf_keybytes(void); - -#define crypto_kdf_PRIMITIVE "blake2b" -SODIUM_EXPORT -const char *crypto_kdf_primitive(void) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len, - uint64_t subkey_id, - const char ctx[crypto_kdf_CONTEXTBYTES], - const unsigned char key[crypto_kdf_KEYBYTES]); - -SODIUM_EXPORT -void crypto_kdf_keygen(unsigned char k[crypto_kdf_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h deleted file mode 100644 index 5480ebe82..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef crypto_kdf_blake2b_H -#define crypto_kdf_blake2b_H - -#include -#include - -#include "crypto_kdf_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kdf_blake2b_BYTES_MIN 16 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_bytes_min(void); - -#define crypto_kdf_blake2b_BYTES_MAX 64 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_bytes_max(void); - -#define crypto_kdf_blake2b_CONTEXTBYTES 8 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_contextbytes(void); - -#define crypto_kdf_blake2b_KEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_keybytes(void); - -SODIUM_EXPORT -int crypto_kdf_blake2b_derive_from_key(unsigned char *subkey, size_t subkey_len, - uint64_t subkey_id, - const char ctx[crypto_kdf_blake2b_CONTEXTBYTES], - const unsigned char key[crypto_kdf_blake2b_KEYBYTES]); -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kx.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kx.h deleted file mode 100644 index d1fce90da..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_kx.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef crypto_kx_H -#define crypto_kx_H - -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kx_PUBLICKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_publickeybytes(void); - -#define crypto_kx_SECRETKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_secretkeybytes(void); - -#define crypto_kx_SEEDBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_seedbytes(void); - -#define crypto_kx_SESSIONKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_sessionkeybytes(void); - -#define crypto_kx_PRIMITIVE "x25519blake2b" -SODIUM_EXPORT -const char *crypto_kx_primitive(void); - -SODIUM_EXPORT -int crypto_kx_seed_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], - unsigned char sk[crypto_kx_SECRETKEYBYTES], - const unsigned char seed[crypto_kx_SEEDBYTES]); - -SODIUM_EXPORT -int crypto_kx_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], - unsigned char sk[crypto_kx_SECRETKEYBYTES]); - -SODIUM_EXPORT -int crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], - unsigned char tx[crypto_kx_SESSIONKEYBYTES], - const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES], - const unsigned char client_sk[crypto_kx_SECRETKEYBYTES], - const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES]) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_kx_server_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], - unsigned char tx[crypto_kx_SESSIONKEYBYTES], - const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES], - const unsigned char server_sk[crypto_kx_SECRETKEYBYTES], - const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES]) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth.h deleted file mode 100644 index 5951c5b82..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef crypto_onetimeauth_H -#define crypto_onetimeauth_H - -#include - -#include "crypto_onetimeauth_poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef crypto_onetimeauth_poly1305_state crypto_onetimeauth_state; - -SODIUM_EXPORT -size_t crypto_onetimeauth_statebytes(void); - -#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES -SODIUM_EXPORT -size_t crypto_onetimeauth_bytes(void); - -#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES -SODIUM_EXPORT -size_t crypto_onetimeauth_keybytes(void); - -#define crypto_onetimeauth_PRIMITIVE "poly1305" -SODIUM_EXPORT -const char *crypto_onetimeauth_primitive(void); - -SODIUM_EXPORT -int crypto_onetimeauth(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -SODIUM_EXPORT -int crypto_onetimeauth_verify(const unsigned char *h, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_onetimeauth_init(crypto_onetimeauth_state *state, - const unsigned char *key); - -SODIUM_EXPORT -int crypto_onetimeauth_update(crypto_onetimeauth_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_onetimeauth_final(crypto_onetimeauth_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_onetimeauth_keygen(unsigned char k[crypto_onetimeauth_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h deleted file mode 100644 index 4b89c4f01..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef crypto_onetimeauth_poly1305_H -#define crypto_onetimeauth_poly1305_H - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#include -#include -#include - -#include - -#include "export.h" - -typedef struct CRYPTO_ALIGN(16) crypto_onetimeauth_poly1305_state { - unsigned char opaque[256]; -} crypto_onetimeauth_poly1305_state; - -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_statebytes(void); - -#define crypto_onetimeauth_poly1305_BYTES 16U -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_bytes(void); - -#define crypto_onetimeauth_poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_keybytes(void); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_init(crypto_onetimeauth_poly1305_state *state, - const unsigned char *key); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_update(crypto_onetimeauth_poly1305_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_final(crypto_onetimeauth_poly1305_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_onetimeauth_poly1305_keygen(unsigned char k[crypto_onetimeauth_poly1305_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash.h deleted file mode 100644 index 7ecd8b071..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef crypto_pwhash_H -#define crypto_pwhash_H - -#include - -#include "crypto_pwhash_argon2i.h" -#include "crypto_pwhash_argon2id.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_ALG_ARGON2I13 crypto_pwhash_argon2i_ALG_ARGON2I13 -SODIUM_EXPORT -int crypto_pwhash_alg_argon2i13(void); - -#define crypto_pwhash_ALG_ARGON2ID13 crypto_pwhash_argon2id_ALG_ARGON2ID13 -SODIUM_EXPORT -int crypto_pwhash_alg_argon2id13(void); - -#define crypto_pwhash_ALG_DEFAULT crypto_pwhash_ALG_ARGON2I13 -SODIUM_EXPORT -int crypto_pwhash_alg_default(void); - -#define crypto_pwhash_BYTES_MIN crypto_pwhash_argon2i_BYTES_MIN -SODIUM_EXPORT -size_t crypto_pwhash_bytes_min(void); - -#define crypto_pwhash_BYTES_MAX crypto_pwhash_argon2i_BYTES_MAX -SODIUM_EXPORT -size_t crypto_pwhash_bytes_max(void); - -#define crypto_pwhash_PASSWD_MIN crypto_pwhash_argon2i_PASSWD_MIN -SODIUM_EXPORT -size_t crypto_pwhash_passwd_min(void); - -#define crypto_pwhash_PASSWD_MAX crypto_pwhash_argon2i_PASSWD_MAX -SODIUM_EXPORT -size_t crypto_pwhash_passwd_max(void); - -#define crypto_pwhash_SALTBYTES crypto_pwhash_argon2i_SALTBYTES -SODIUM_EXPORT -size_t crypto_pwhash_saltbytes(void); - -#define crypto_pwhash_STRBYTES crypto_pwhash_argon2i_STRBYTES -SODIUM_EXPORT -size_t crypto_pwhash_strbytes(void); - -#define crypto_pwhash_STRPREFIX crypto_pwhash_argon2i_STRPREFIX -SODIUM_EXPORT -const char *crypto_pwhash_strprefix(void); - -#define crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_argon2i_OPSLIMIT_MIN -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_min(void); - -#define crypto_pwhash_OPSLIMIT_MAX crypto_pwhash_argon2i_OPSLIMIT_MAX -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_max(void); - -#define crypto_pwhash_MEMLIMIT_MIN crypto_pwhash_argon2i_MEMLIMIT_MIN -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_min(void); - -#define crypto_pwhash_MEMLIMIT_MAX crypto_pwhash_argon2i_MEMLIMIT_MAX -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_max(void); - -#define crypto_pwhash_OPSLIMIT_INTERACTIVE crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_interactive(void); - -#define crypto_pwhash_MEMLIMIT_INTERACTIVE crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_interactive(void); - -#define crypto_pwhash_OPSLIMIT_MODERATE crypto_pwhash_argon2i_OPSLIMIT_MODERATE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_moderate(void); - -#define crypto_pwhash_MEMLIMIT_MODERATE crypto_pwhash_argon2i_MEMLIMIT_MODERATE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_moderate(void); - -#define crypto_pwhash_OPSLIMIT_SENSITIVE crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_sensitive(void); - -#define crypto_pwhash_MEMLIMIT_SENSITIVE crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_sensitive(void); - -/* - * With this function, do not forget to store all parameters, including the - * algorithm identifier in order to produce deterministic output. - */ -SODIUM_EXPORT -int crypto_pwhash(unsigned char * const out, unsigned long long outlen, - const char * const passwd, unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, int alg) - __attribute__ ((warn_unused_result)); - -/* - * The output string already includes all the required parameters, including - * the algorithm identifier. The string is all that has to be stored in - * order to verify a password. - */ -SODIUM_EXPORT -int crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], - const char * const passwd, unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_str_verify(const char str[crypto_pwhash_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -#define crypto_pwhash_PRIMITIVE "argon2i" -SODIUM_EXPORT -const char *crypto_pwhash_primitive(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h deleted file mode 100644 index fed965878..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef crypto_pwhash_argon2i_H -#define crypto_pwhash_argon2i_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_argon2i_ALG_ARGON2I13 1 -SODIUM_EXPORT -int crypto_pwhash_argon2i_alg_argon2i13(void); - -#define crypto_pwhash_argon2i_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_bytes_min(void); - -#define crypto_pwhash_argon2i_BYTES_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_bytes_max(void); - -#define crypto_pwhash_argon2i_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_passwd_min(void); - -#define crypto_pwhash_argon2i_PASSWD_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_passwd_max(void); - -#define crypto_pwhash_argon2i_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_saltbytes(void); - -#define crypto_pwhash_argon2i_STRBYTES 128U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_strbytes(void); - -#define crypto_pwhash_argon2i_STRPREFIX "$argon2i$" -SODIUM_EXPORT -const char *crypto_pwhash_argon2i_strprefix(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MIN 3U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_min(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_max(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MIN 8192U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_min(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MAX ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_max(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE 4U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_interactive(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE 33554432U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_interactive(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MODERATE 6U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_moderate(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MODERATE 134217728U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_moderate(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE 8U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_sensitive(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE 536870912U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_argon2i(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, - int alg) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h deleted file mode 100644 index 550fd6fd5..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef crypto_pwhash_argon2id_H -#define crypto_pwhash_argon2id_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_argon2id_ALG_ARGON2ID13 2 -SODIUM_EXPORT -int crypto_pwhash_argon2id_alg_argon2id13(void); - -#define crypto_pwhash_argon2id_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_bytes_min(void); - -#define crypto_pwhash_argon2id_BYTES_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_bytes_max(void); - -#define crypto_pwhash_argon2id_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_passwd_min(void); - -#define crypto_pwhash_argon2id_PASSWD_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_passwd_max(void); - -#define crypto_pwhash_argon2id_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_saltbytes(void); - -#define crypto_pwhash_argon2id_STRBYTES 128U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_strbytes(void); - -#define crypto_pwhash_argon2id_STRPREFIX "$argon2id$" -SODIUM_EXPORT -const char *crypto_pwhash_argon2id_strprefix(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MIN 1U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_min(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_max(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MIN 8192U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_min(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MAX ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_max(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE 2U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_interactive(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE 67108864U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_interactive(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MODERATE 3U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_moderate(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MODERATE 268435456U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_moderate(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE 4U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_sensitive(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE 1073741824U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_argon2id(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, - int alg) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h deleted file mode 100644 index 987f123fb..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef crypto_pwhash_scryptsalsa208sha256_H -#define crypto_pwhash_scryptsalsa208sha256_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_scryptsalsa208sha256_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_bytes_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_BYTES_MAX (SIZE_MAX > 0x1fffffffe0ULL ? 0x1fffffffe0ULL : SIZE_MAX) -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_bytes_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_passwd_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX SIZE_MAX -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_passwd_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void); - -#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void); - -#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" -SODIUM_EXPORT -const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN 32768U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN 16777216U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX ((SIZE_MAX >= 68719476736U) ? 68719476736U : SIZE_MAX) -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, - size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, - size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, - const uint8_t * salt, size_t saltlen, - uint64_t N, uint32_t r, uint32_t p, - uint8_t * buf, size_t buflen) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult.h deleted file mode 100644 index 830c10f64..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef crypto_scalarmult_H -#define crypto_scalarmult_H - -#include - -#include "crypto_scalarmult_curve25519.h" -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES -SODIUM_EXPORT -size_t crypto_scalarmult_bytes(void); - -#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES -SODIUM_EXPORT -size_t crypto_scalarmult_scalarbytes(void); - -#define crypto_scalarmult_PRIMITIVE "curve25519" -SODIUM_EXPORT -const char *crypto_scalarmult_primitive(void); - -SODIUM_EXPORT -int crypto_scalarmult_base(unsigned char *q, const unsigned char *n); - -SODIUM_EXPORT -int crypto_scalarmult(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h deleted file mode 100644 index d96840c73..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef crypto_scalarmult_curve25519_H -#define crypto_scalarmult_curve25519_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_curve25519_BYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_curve25519_bytes(void); - -#define crypto_scalarmult_curve25519_SCALARBYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_curve25519_scalarbytes(void); - -SODIUM_EXPORT -int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox.h deleted file mode 100644 index 9b098200e..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef crypto_secretbox_H -#define crypto_secretbox_H - -#include - -#include "crypto_secretbox_xsalsa20poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES -SODIUM_EXPORT -size_t crypto_secretbox_keybytes(void); - -#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES -SODIUM_EXPORT -size_t crypto_secretbox_noncebytes(void); - -#define crypto_secretbox_MACBYTES crypto_secretbox_xsalsa20poly1305_MACBYTES -SODIUM_EXPORT -size_t crypto_secretbox_macbytes(void); - -#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" -SODIUM_EXPORT -const char *crypto_secretbox_primitive(void); - -SODIUM_EXPORT -int crypto_secretbox_easy(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_secretbox_detached(unsigned char *c, unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_secretbox_keygen(unsigned char k[crypto_secretbox_KEYBYTES]); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES -SODIUM_EXPORT -size_t crypto_secretbox_zerobytes(void); - -#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES -SODIUM_EXPORT -size_t crypto_secretbox_boxzerobytes(void); - -SODIUM_EXPORT -int crypto_secretbox(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h deleted file mode 100644 index 7a61a0917..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef crypto_secretbox_xchacha20poly1305_H -#define crypto_secretbox_xchacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_xchacha20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_keybytes(void); - -#define crypto_secretbox_xchacha20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_noncebytes(void); - -#define crypto_secretbox_xchacha20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_macbytes(void); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_easy(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_open_easy(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_detached(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h deleted file mode 100644 index 5aa30805d..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef crypto_secretbox_xsalsa20poly1305_H -#define crypto_secretbox_xsalsa20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_xsalsa20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_keybytes(void); - -#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_noncebytes(void); - -#define crypto_secretbox_xsalsa20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_macbytes(void); - -#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_boxzerobytes(void); - -#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES \ - (crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES + \ - crypto_secretbox_xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_zerobytes(void); - -SODIUM_EXPORT -int crypto_secretbox_xsalsa20poly1305(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_xsalsa20poly1305_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_secretbox_xsalsa20poly1305_keygen(unsigned char k[crypto_secretbox_xsalsa20poly1305_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash.h deleted file mode 100644 index a49880824..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef crypto_shorthash_H -#define crypto_shorthash_H - -#include - -#include "crypto_shorthash_siphash24.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_shorthash_BYTES crypto_shorthash_siphash24_BYTES -SODIUM_EXPORT -size_t crypto_shorthash_bytes(void); - -#define crypto_shorthash_KEYBYTES crypto_shorthash_siphash24_KEYBYTES -SODIUM_EXPORT -size_t crypto_shorthash_keybytes(void); - -#define crypto_shorthash_PRIMITIVE "siphash24" -SODIUM_EXPORT -const char *crypto_shorthash_primitive(void); - -SODIUM_EXPORT -int crypto_shorthash(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -SODIUM_EXPORT -void crypto_shorthash_keygen(unsigned char k[crypto_shorthash_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h deleted file mode 100644 index 745ed48fa..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef crypto_shorthash_siphash24_H -#define crypto_shorthash_siphash24_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -/* -- 64-bit output -- */ - -#define crypto_shorthash_siphash24_BYTES 8U -SODIUM_EXPORT -size_t crypto_shorthash_siphash24_bytes(void); - -#define crypto_shorthash_siphash24_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphash24_keybytes(void); - -SODIUM_EXPORT -int crypto_shorthash_siphash24(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -#ifndef SODIUM_LIBRARY_MINIMAL -/* -- 128-bit output -- */ - -#define crypto_shorthash_siphashx24_BYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphashx24_bytes(void); - -#define crypto_shorthash_siphashx24_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphashx24_keybytes(void); - -SODIUM_EXPORT -int crypto_shorthash_siphashx24(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign.h deleted file mode 100644 index b0335bf27..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef crypto_sign_H -#define crypto_sign_H - -/* - * THREAD SAFETY: crypto_sign_keypair() is thread-safe, - * provided that sodium_init() was called before. - * - * Other functions, including crypto_sign_seed_keypair() are always thread-safe. - */ - -#include - -#include "crypto_sign_ed25519.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef crypto_sign_ed25519ph_state crypto_sign_state; - -SODIUM_EXPORT -size_t crypto_sign_statebytes(void); - -#define crypto_sign_BYTES crypto_sign_ed25519_BYTES -SODIUM_EXPORT -size_t crypto_sign_bytes(void); - -#define crypto_sign_SEEDBYTES crypto_sign_ed25519_SEEDBYTES -SODIUM_EXPORT -size_t crypto_sign_seedbytes(void); - -#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES -SODIUM_EXPORT -size_t crypto_sign_publickeybytes(void); - -#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES -SODIUM_EXPORT -size_t crypto_sign_secretkeybytes(void); - -#define crypto_sign_PRIMITIVE "ed25519" -SODIUM_EXPORT -const char *crypto_sign_primitive(void); - -SODIUM_EXPORT -int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_sign_keypair(unsigned char *pk, unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign(unsigned char *sm, unsigned long long *smlen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_open(unsigned char *m, unsigned long long *mlen_p, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_detached(unsigned char *sig, unsigned long long *siglen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_verify_detached(const unsigned char *sig, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_init(crypto_sign_state *state); - -SODIUM_EXPORT -int crypto_sign_update(crypto_sign_state *state, - const unsigned char *m, unsigned long long mlen); - -SODIUM_EXPORT -int crypto_sign_final_create(crypto_sign_state *state, unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_final_verify(crypto_sign_state *state, unsigned char *sig, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_ed25519.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_ed25519.h deleted file mode 100644 index 17c150f28..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_ed25519.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef crypto_sign_ed25519_H -#define crypto_sign_ed25519_H - -#include -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_sign_ed25519ph_state { - crypto_hash_sha512_state hs; -} crypto_sign_ed25519ph_state; - -SODIUM_EXPORT -size_t crypto_sign_ed25519ph_statebytes(void); - -#define crypto_sign_ed25519_BYTES 64U -SODIUM_EXPORT -size_t crypto_sign_ed25519_bytes(void); - -#define crypto_sign_ed25519_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_sign_ed25519_seedbytes(void); - -#define crypto_sign_ed25519_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_sign_ed25519_publickeybytes(void); - -#define crypto_sign_ed25519_SECRETKEYBYTES (32U + 32U) -SODIUM_EXPORT -size_t crypto_sign_ed25519_secretkeybytes(void); - -SODIUM_EXPORT -int crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen_p, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_ed25519_detached(unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_verify_detached(const unsigned char *sig, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_ed25519_keypair(unsigned char *pk, unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_sign_ed25519_pk_to_curve25519(unsigned char *curve25519_pk, - const unsigned char *ed25519_pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_curve25519(unsigned char *curve25519_sk, - const unsigned char *ed25519_sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_seed(unsigned char *seed, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_init(crypto_sign_ed25519ph_state *state); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_update(crypto_sign_ed25519ph_state *state, - const unsigned char *m, - unsigned long long mlen); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_final_create(crypto_sign_ed25519ph_state *state, - unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_final_verify(crypto_sign_ed25519ph_state *state, - unsigned char *sig, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h deleted file mode 100644 index 2224a94e0..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef crypto_sign_edwards25519sha512batch_H -#define crypto_sign_edwards25519sha512batch_H - -/* - * WARNING: This construction was a prototype, which should not be used - * any more in new projects. - * - * crypto_sign_edwards25519sha512batch is provided for applications - * initially built with NaCl, but as recommended by the author of this - * construction, new applications should use ed25519 instead. - * - * In Sodium, you should use the high-level crypto_sign_*() functions instead. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_sign_edwards25519sha512batch_BYTES 64U -#define crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES 32U -#define crypto_sign_edwards25519sha512batch_SECRETKEYBYTES (32U + 32U) - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch(unsigned char *sm, - unsigned long long *smlen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *sk) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch_open(unsigned char *m, - unsigned long long *mlen_p, - const unsigned char *sm, - unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch_keypair(unsigned char *pk, - unsigned char *sk) - __attribute__ ((deprecated)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream.h deleted file mode 100644 index 22de6ff52..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef crypto_stream_H -#define crypto_stream_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include - -#include "crypto_stream_xsalsa20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES -SODIUM_EXPORT -size_t crypto_stream_keybytes(void); - -#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES -SODIUM_EXPORT -size_t crypto_stream_noncebytes(void); - -#define crypto_stream_PRIMITIVE "xsalsa20" -SODIUM_EXPORT -const char *crypto_stream_primitive(void); - -SODIUM_EXPORT -int crypto_stream(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_keygen(unsigned char k[crypto_stream_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h deleted file mode 100644 index 33ee1b897..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef crypto_stream_aes128ctr_H -#define crypto_stream_aes128ctr_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_aes128ctr_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_stream_aes128ctr_keybytes(void); - -#define crypto_stream_aes128ctr_NONCEBYTES 16U -SODIUM_EXPORT -size_t crypto_stream_aes128ctr_noncebytes(void); - -#define crypto_stream_aes128ctr_BEFORENMBYTES 1408U -SODIUM_EXPORT -size_t crypto_stream_aes128ctr_beforenmbytes(void); - -SODIUM_EXPORT -int crypto_stream_aes128ctr(unsigned char *out, unsigned long long outlen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_xor(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_beforenm(unsigned char *c, const unsigned char *k) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_afternm(unsigned char *out, unsigned long long len, - const unsigned char *nonce, const unsigned char *c) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_xor_afternm(unsigned char *out, const unsigned char *in, - unsigned long long len, - const unsigned char *nonce, - const unsigned char *c) - __attribute__ ((deprecated)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_chacha20.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_chacha20.h deleted file mode 100644 index 352b92904..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_chacha20.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef crypto_stream_chacha20_H -#define crypto_stream_chacha20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_chacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_chacha20_keybytes(void); - -#define crypto_stream_chacha20_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_chacha20_noncebytes(void); - -/* ChaCha20 with a 64-bit nonce and a 64-bit counter, as originally designed */ - -SODIUM_EXPORT -int crypto_stream_chacha20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_chacha20_keygen(unsigned char k[crypto_stream_chacha20_KEYBYTES]); - -/* ChaCha20 with a 96-bit nonce and a 32-bit counter (IETF) */ - -#define crypto_stream_chacha20_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_chacha20_ietf_keybytes(void); - -#define crypto_stream_chacha20_ietf_NONCEBYTES 12U -SODIUM_EXPORT -size_t crypto_stream_chacha20_ietf_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint32_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_chacha20_ietf_keygen(unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]); - -/* Aliases */ - -#define crypto_stream_chacha20_IETF_KEYBYTES crypto_stream_chacha20_ietf_KEYBYTES -#define crypto_stream_chacha20_IETF_NONCEBYTES crypto_stream_chacha20_ietf_NONCEBYTES - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa20.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa20.h deleted file mode 100644 index 961e5c1c5..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa20.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_stream_salsa20_H -#define crypto_stream_salsa20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa20_keybytes(void); - -#define crypto_stream_salsa20_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa20_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_salsa20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_salsa20_keygen(unsigned char k[crypto_stream_salsa20_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h deleted file mode 100644 index d5c442821..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef crypto_stream_salsa2012_H -#define crypto_stream_salsa2012_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa2012_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa2012_keybytes(void); - -#define crypto_stream_salsa2012_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa2012_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_salsa2012(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_salsa2012_keygen(unsigned char k[crypto_stream_salsa2012_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa208.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa208.h deleted file mode 100644 index 02b4166e1..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_salsa208.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef crypto_stream_salsa208_H -#define crypto_stream_salsa208_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa208_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa208_keybytes(void); - -#define crypto_stream_salsa208_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa208_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_salsa208(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa208_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_salsa208_keygen(unsigned char k[crypto_stream_salsa208_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h deleted file mode 100644 index f884798e7..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_stream_xchacha20_H -#define crypto_stream_xchacha20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_xchacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_xchacha20_keybytes(void); - -#define crypto_stream_xchacha20_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_stream_xchacha20_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_xchacha20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xchacha20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xchacha20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_xchacha20_keygen(unsigned char k[crypto_stream_xchacha20_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h deleted file mode 100644 index ed5ae3c3d..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_stream_xsalsa20_H -#define crypto_stream_xsalsa20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_xsalsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_xsalsa20_keybytes(void); - -#define crypto_stream_xsalsa20_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_stream_xsalsa20_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_xsalsa20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xsalsa20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xsalsa20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_xsalsa20_keygen(unsigned char k[crypto_stream_xsalsa20_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_16.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_16.h deleted file mode 100644 index 5e9eeabee..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_16.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_16_H -#define crypto_verify_16_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_16_BYTES 16U -SODIUM_EXPORT -size_t crypto_verify_16_bytes(void); - -SODIUM_EXPORT -int crypto_verify_16(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_32.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_32.h deleted file mode 100644 index 281b5a1bb..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_32.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_32_H -#define crypto_verify_32_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_32_BYTES 32U -SODIUM_EXPORT -size_t crypto_verify_32_bytes(void); - -SODIUM_EXPORT -int crypto_verify_32(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_64.h b/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_64.h deleted file mode 100644 index 0dc7c304a..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/crypto_verify_64.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_64_H -#define crypto_verify_64_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_64_BYTES 64U -SODIUM_EXPORT -size_t crypto_verify_64_bytes(void); - -SODIUM_EXPORT -int crypto_verify_64(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/export.h b/src/Native/libetchash/windows/include/libsodium/sodium/export.h deleted file mode 100644 index c33bced81..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/export.h +++ /dev/null @@ -1,44 +0,0 @@ - -#ifndef sodium_export_H -#define sodium_export_H - -#ifndef __GNUC__ -# ifdef __attribute__ -# undef __attribute__ -# endif -# define __attribute__(a) -#endif - -#ifdef SODIUM_STATIC -# define SODIUM_EXPORT -#else -# if defined(_MSC_VER) -# ifdef SODIUM_DLL_EXPORT -# define SODIUM_EXPORT __declspec(dllexport) -# else -# define SODIUM_EXPORT __declspec(dllimport) -# endif -# else -# if defined(__SUNPRO_C) -# ifndef __GNU_C__ -# define SODIUM_EXPORT __attribute__ (visibility(__global)) -# else -# define SODIUM_EXPORT __attribute__ __global -# endif -# elif defined(_MSG_VER) -# define SODIUM_EXPORT extern __declspec(dllexport) -# else -# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) -# endif -# endif -#endif - -#ifndef CRYPTO_ALIGN -# if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# define CRYPTO_ALIGN(x) __declspec(align(x)) -# else -# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) -# endif -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/randombytes.h b/src/Native/libetchash/windows/include/libsodium/sodium/randombytes.h deleted file mode 100644 index d112fb293..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/randombytes.h +++ /dev/null @@ -1,66 +0,0 @@ - -#ifndef randombytes_H -#define randombytes_H - -#include -#include - -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct randombytes_implementation { - const char *(*implementation_name)(void); /* required */ - uint32_t (*random)(void); /* required */ - void (*stir)(void); /* optional */ - uint32_t (*uniform)(const uint32_t upper_bound); /* optional, a default implementation will be used if NULL */ - void (*buf)(void * const buf, const size_t size); /* required */ - int (*close)(void); /* optional */ -} randombytes_implementation; - -#define randombytes_SEEDBYTES 32U -SODIUM_EXPORT -size_t randombytes_seedbytes(void); - -SODIUM_EXPORT -void randombytes_buf(void * const buf, const size_t size); - -SODIUM_EXPORT -void randombytes_buf_deterministic(void * const buf, const size_t size, - const unsigned char seed[randombytes_SEEDBYTES]); - -SODIUM_EXPORT -uint32_t randombytes_random(void); - -SODIUM_EXPORT -uint32_t randombytes_uniform(const uint32_t upper_bound); - -SODIUM_EXPORT -void randombytes_stir(void); - -SODIUM_EXPORT -int randombytes_close(void); - -SODIUM_EXPORT -int randombytes_set_implementation(randombytes_implementation *impl); - -SODIUM_EXPORT -const char *randombytes_implementation_name(void); - -/* -- NaCl compatibility interface -- */ - -SODIUM_EXPORT -void randombytes(unsigned char * const buf, const unsigned long long buf_len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/randombytes_salsa20_random.h b/src/Native/libetchash/windows/include/libsodium/sodium/randombytes_salsa20_random.h deleted file mode 100644 index 4deae15b6..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/randombytes_salsa20_random.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef randombytes_salsa20_random_H -#define randombytes_salsa20_random_H - -#include "export.h" -#include "randombytes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -extern struct randombytes_implementation randombytes_salsa20_implementation; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/randombytes_sysrandom.h b/src/Native/libetchash/windows/include/libsodium/sodium/randombytes_sysrandom.h deleted file mode 100644 index 9e27b674c..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/randombytes_sysrandom.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef randombytes_sysrandom_H -#define randombytes_sysrandom_H - -#include "export.h" -#include "randombytes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -extern struct randombytes_implementation randombytes_sysrandom_implementation; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/runtime.h b/src/Native/libetchash/windows/include/libsodium/sodium/runtime.h deleted file mode 100644 index 76859ea0e..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/runtime.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef sodium_runtime_H -#define sodium_runtime_H - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -int sodium_runtime_has_neon(void); - -SODIUM_EXPORT -int sodium_runtime_has_sse2(void); - -SODIUM_EXPORT -int sodium_runtime_has_sse3(void); - -SODIUM_EXPORT -int sodium_runtime_has_ssse3(void); - -SODIUM_EXPORT -int sodium_runtime_has_sse41(void); - -SODIUM_EXPORT -int sodium_runtime_has_avx(void); - -SODIUM_EXPORT -int sodium_runtime_has_avx2(void); - -SODIUM_EXPORT -int sodium_runtime_has_pclmul(void); - -SODIUM_EXPORT -int sodium_runtime_has_aesni(void); - -/* ------------------------------------------------------------------------- */ - -int _sodium_runtime_get_cpu_features(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/utils.h b/src/Native/libetchash/windows/include/libsodium/sodium/utils.h deleted file mode 100644 index 0a7aadb43..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/utils.h +++ /dev/null @@ -1,131 +0,0 @@ - -#ifndef sodium_utils_H -#define sodium_utils_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef SODIUM_C99 -# if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L -# define SODIUM_C99(X) -# else -# define SODIUM_C99(X) X -# endif -#endif - -SODIUM_EXPORT -void sodium_memzero(void * const pnt, const size_t len); - -/* - * WARNING: sodium_memcmp() must be used to verify if two secret keys - * are equal, in constant time. - * It returns 0 if the keys are equal, and -1 if they differ. - * This function is not designed for lexicographical comparisons. - */ -SODIUM_EXPORT -int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len) - __attribute__ ((warn_unused_result)); - -/* - * sodium_compare() returns -1 if b1_ < b2_, 1 if b1_ > b2_ and 0 if b1_ == b2_ - * It is suitable for lexicographical comparisons, or to compare nonces - * and counters stored in little-endian format. - * However, it is slower than sodium_memcmp(). - */ -SODIUM_EXPORT -int sodium_compare(const unsigned char *b1_, const unsigned char *b2_, - size_t len) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int sodium_is_zero(const unsigned char *n, const size_t nlen); - -SODIUM_EXPORT -void sodium_increment(unsigned char *n, const size_t nlen); - -SODIUM_EXPORT -void sodium_add(unsigned char *a, const unsigned char *b, const size_t len); - -SODIUM_EXPORT -char *sodium_bin2hex(char * const hex, const size_t hex_maxlen, - const unsigned char * const bin, const size_t bin_len); - -SODIUM_EXPORT -int sodium_hex2bin(unsigned char * const bin, const size_t bin_maxlen, - const char * const hex, const size_t hex_len, - const char * const ignore, size_t * const bin_len, - const char ** const hex_end); - -SODIUM_EXPORT -int sodium_mlock(void * const addr, const size_t len); - -SODIUM_EXPORT -int sodium_munlock(void * const addr, const size_t len); - -/* WARNING: sodium_malloc() and sodium_allocarray() are not general-purpose - * allocation functions. - * - * They return a pointer to a region filled with 0xd0 bytes, immediately - * followed by a guard page. - * As a result, accessing a single byte after the requested allocation size - * will intentionally trigger a segmentation fault. - * - * A canary and an additional guard page placed before the beginning of the - * region may also kill the process if a buffer underflow is detected. - * - * The memory layout is: - * [unprotected region size (read only)][guard page (no access)][unprotected pages (read/write)][guard page (no access)] - * With the layout of the unprotected pages being: - * [optional padding][16-bytes canary][user region] - * - * However: - * - These functions are significantly slower than standard functions - * - Each allocation requires 3 or 4 additional pages - * - The returned address will not be aligned if the allocation size is not - * a multiple of the required alignment. For this reason, these functions - * are designed to store data, such as secret keys and messages. - * - * sodium_malloc() can be used to allocate any libsodium data structure. - * - * The crypto_generichash_state structure is packed and its length is - * either 357 or 361 bytes. For this reason, when using sodium_malloc() to - * allocate a crypto_generichash_state structure, padding must be added in - * order to ensure proper alignment. crypto_generichash_statebytes() - * returns the rounded up structure size, and should be prefered to sizeof(): - * state = sodium_malloc(crypto_generichash_statebytes()); - */ - -SODIUM_EXPORT -void *sodium_malloc(const size_t size) - __attribute__ ((malloc)); - -SODIUM_EXPORT -void *sodium_allocarray(size_t count, size_t size) - __attribute__ ((malloc)); - -SODIUM_EXPORT -void sodium_free(void *ptr); - -SODIUM_EXPORT -int sodium_mprotect_noaccess(void *ptr); - -SODIUM_EXPORT -int sodium_mprotect_readonly(void *ptr); - -SODIUM_EXPORT -int sodium_mprotect_readwrite(void *ptr); - -/* -------- */ - -int _sodium_alloc_init(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/include/libsodium/sodium/version.h b/src/Native/libetchash/windows/include/libsodium/sodium/version.h deleted file mode 100644 index ab8839f79..000000000 --- a/src/Native/libetchash/windows/include/libsodium/sodium/version.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef sodium_version_H -#define sodium_version_H - -#include "export.h" - -#define SODIUM_VERSION_STRING "1.0.13" - -#define SODIUM_LIBRARY_VERSION_MAJOR 9 -#define SODIUM_LIBRARY_VERSION_MINOR 5 - - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -const char *sodium_version_string(void); - -SODIUM_EXPORT -int sodium_library_version_major(void); - -SODIUM_EXPORT -int sodium_library_version_minor(void); - -SODIUM_EXPORT -int sodium_library_minimal(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libetchash/windows/lib/x64/libsodium.lib b/src/Native/libetchash/windows/lib/x64/libsodium.lib deleted file mode 100644 index 1e9bb80b80b236113b098c5082a905f61b956656..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1885178 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
FkG_dOotj56pY+$z=*fR$9f`P3y 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

iq2S8Qir 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ͻ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 z zxtL7>QIb}UTo7lbsHX2e+Bz_IqDeWfB?Rg&R1vX=2ir&?eyqhK1>%QxVr)0>!R8j+ z`>^@S{yA*6MXY+o@cPRGHZk)02W+-6`crhr;wKkq(3jIVha?zRWZJQ3qLA`3%?DDQMpU7j}$uuy^dgqTUXdSL$Q&H zak*FM<|@V|R>9_5SJ+#s*fokl|2pzWarW4YkX!TZU)(H~iC+4E`caweJ-xaRzwyh@ z|MH0!Zckl{l_#%1e%$O6h44JH3?vx4BoqS9yZffEb+TY-*r6f~9%u6%M8BaN4_nmz$G?g6Rb7O3d1#|^kJ7HkfG<6)Br!kdqR6KA|V z@e}2IxqY*!zQGe^zV&s;uxk*}BY)JmV%z>it^pPkDFU zz^U1n9vgWi0|z0#a+3j6v+5{R-0Oe;%9fh-ZHHxTKB+pp;?Jmf^&3jguRB;2?29wa zZE}dq>%E%u1`Z62%pbXz($kuAV6*s{SsGR}&IyQdMe_{ncK&VQA@?)L=zMyD|5*6% zXZj=IQCKAW}27=6oU6$Kt<+3$=dq=Jcu$=Lp!0k)__2gDnpBiKq&_lu$Tig*z1Sd@3C3 zQEZW7S1HEvNBD8mQsO-stwXRP>oN`3+&YP7o7el(+J>sr>!#-6F0I}#4%?=7P}@h3m?DfRGEI#XBF?)Pt6-Q9y4^gY@=pf4u+5eyKb&4&I?V=uHOujCrZw* zUwhuvwdQJyscX3%bpn3Dt#}rEXjq&yY{l#jSwZ-lh98ad|2h2kGd@!7SgJJ6{}cGT z>nO-)vhnr(N3(B5C8c32J`40c5?V3S#IUR-ziW?w#w;$KC&Q7c;!z|{h9aJlVIw%u zP>sVeB)L8@!#q#LlqrgB^Gtk*pp7;^=1hz~Z21#ZRC9OMgp5ZTO5RS;^hn0mAT6Ks zP=@SeLiz`DB-;cfS_;jN7A;BU#nNpE@kCsY>qqUROa|?3zD*ps^!-2_GH}y&wiMTa zNcS@V+29=xa=r+%omaY0I+@Trh&+cOfql%e7B+6QH1>h+;E}vJ z9GBED(Vxxu5EG<}j^Z0pnCyKFZ2$Q(;deXSD9+;LD9-sVDHypHOXJRmBosDDtO(-{ za9jh_8P=;p{3wxcSrAj67;8g6*etFAu%oa~g3TTXy-utf>{DR(h0OyVr^7CSeI{&3 zE;bVOP}t|fhF=W5nK_^_9rhqR&$Q3X2;-NYi7x4x=n8vpTHh>QFlgw)oN?Pe^JB$$ zoI=93x2~|)U$K)EVm}ECl10fY8+`cAsLuQf$3q&nm`GYD(BYEB2{k zUns`;wa{^XE%EkHte0Zr6l1?2beAYrt=MkGc*TLxVSbGX4La1kNtg-MzE+iw*--si z*)?B;Dx&opFz>0^a@v|5ZO^D;>EJ)9F0Vj;F781^Aeca?0b zjVDP5nvh+*BQ3X1%8fmpaAW%s<9DC_1PyK9PSB+Dm5I{;OuPJk-$~YW!0b27i;ZC$ zKkdS{J4`RHD|*en)@9i)3K?qDWtn8h^;y$Q-13j*%X-1_aH2pw7-wElj)l!qKtB~b z4EFJ``D%jx%3K}O12*dh%TD#dv8SomF|7*8z-#>-uV-_we*R}zdpkkGxU z7>eFv>DCoC*QyKMQpM1B@Ff1Kdw%hYUtl&CU7r00UtvCbYt4IYmJg1cv>|f!Z}5E5 z(~%_)(tahf)fZ=fR+>}$vi%NX7KRJ2C{nZ3c=4NwotKXe%|0CS zw)JiEXKe`e&%ZVXKku4BZEDt})vxcmCT+vmaoY&hZ{(!zcU414o)hTRWdasz8~MmQ zFn4+OsVA+e46g^5_2-wMUpv19*Qa4BX#TVMN$VF93Yx}-wa9z$v7#F_U_)ClDJdrmd_D@*n zWty0Vt@!aSWigB0R=lr1>d&$4ZBFd3IPWPjK@QO#hB*=AcYtnA6~APf>B!Ja@fC~d z^y&O1Q%OIG{T|CKkDw!R{h#!0K|Pb7Y&)-UH-mGq!I#r;lW`l|R_u3g?9RkUbnF~V zbjX(+DR+~?8HQ{DR)Nzs^U|TyLqfAC{3O`bMkaxTlHQl_RmU`3th}ExapmWjL_zDH z;htBD`%|6pkARow9b=zEwhE{tha_3^SJaaiOkw6$Yrf;>TmB<<}Q? zt}EVDePryaQ2**fV^_7wuRbvH$gni57jBMQFRW_MF{AN!BkGGc^ZL#;yZF~CC)zzPO{Rq*ft*hl_^ zADZm0EZwv`yLZ~C&0v7fcGPcJAIcwuA$hGEl6Q)S%|$*^df4*pBTo9Lvg7);UOh(H zL`mVE^3@o7Uub;s_yDA>Ezj`VWmUc~;sq2#Zax0@GOiz~YZY9_7>pYv-HodO|1r%2 zmkdFMVT^0>rZs;a0yR{_= z{%>P|PB*?n$Az%?@ZH-YkR9NE3D>*$#rt1t{If}97J>$X-w6o=Jk!K9@XBR=BteW0 z@Vqng)ZFv%G7{3Aufe&zsr7I}xmZuMZ=8IVdFTmg~ikSUh{E`k;pjI zHNBIYWjG$8b0?0foKI~;YEsM^FaW`HHi_Ue73&6xq%g05Yho7rJXo%)AX}2KBOucTx$&`n!;(qhIKSUyYA2rY0Or_%N z10qqqMcGu?Xi$v4n7xTe+(hX&P&GZl%-G}uCcKrx6p2xfvb9tgBIMxQR~u#abghQ| z4h#JHz7!KkGLkxuBnQflqOhOjZFC8)}cQnq~^)0B>M!fsvKJyN|#hx!hRU`1+bUF290+O?3-ZM!Tv7n>tNpv zdpYcTVc!7zLD=7cy$1Hpu%Cf_3v5;~go!;18zXg$^Y9G%( z{s{JwVoZZz`+=K;ZD(C!uZLnhO)Yfn0)=j{Vw{=^Hc2s#mVzx)jQ7wA_JCsR6x*oS zhl+iy*g+VLB`iN2Kv&p1PBDJFMX>&gout?>#YQN0o?<16)hR|@HsSZUVyhK_o-RRE&$D!tVmbc>A4TS1VSp81H_Oc-JcS zqGG(?PQw00v3C>;rMs~ESr;?~6+2k5F^Wx4>=MPew=8iiR;*UBTNL|&Vs|O_bHyH3 z>^F+7!7NGg_KbCfz1J1nqF9d;3VZhI-KTHA{sRUM8a!lZ@#(|P7=Gr6k)uYB89Q$L zgo$TOntb*-=T5(1#>~=L7hY60`{Frs=atXDq@uE_`qBjpFS~pns^d*-hdR;7v`!tb z5}47fq^5dxyf0 zp@;nbkN`gW!zV4Y1?iCqCMS@TS^Q!2x487I50cXpF*MYSIu0(HRG0R0 zKqALkSJpq4%!g7*3sEC#44J^lrM>(a0D5Wjfz8dM4txiK9=Vv|NNuF^Zx#>~e`8tJ)|1nIeywC0jOYDvv2 zudIYRsavfj)CdT^2+-d9S5ZB$s%&m)31&nL)hqr2K)DdmofdFAU?mRlN*bMO^PlWi zSra;{_Ljin!9^p6jT|v@?2sWvr}a6lXVYD6;1z=569)9_**of+=I#*e*|+b&o`#%v z2=?&)`2MZuT#NbLw`_q0>9!7K=M`@PbXzB)(N`wW6{XN^-4Hj8CR;<7pxesn;1F~! zyV$|Nuw4e}K5jw})*0QwcH13tF*ry!6CHwg6z1mfCWzk_5EOteldl&r?8}1qF+C?* z8q(1O@#8zzsh~ULKtqy}AJaF|(glxCrtbkuBb34N+X~M|K=;E#n&b22a}2)>tCjuk{HV1{BD6?Ht4on+En~l z9*4_vm*tk4Uq0y4+0bB`;@8j82xTxomdDAUi$;a2DSqQEjZmiMcQ)uwKC)?kl;1o{ z(-c3p-wM!;KB{ScocYBpO>_KeKv!a?T}|cpMmIIH41?+m)Av2lRptv(Dt?%9d3S;4 zrelPT^T;56tB{fHpt-Y)(5326N5K2fSlBzpPLB{QkRQ*y4*|`$y9+;d!9o2g>))sz zLgW4irH}cY0J;-S5UN!9CBNyQxzN&u@SKX@C7>C_H4Yf%m!LbJ1;48-jUmLpqMX7a z45h8no&Pz4U+jgdp8CbB($Zf|^>6T#d$T34kluQ_YZZVX; z#4qMqzj2etj2}9oWccV3LxuN>OcPkLQ-WK#N@kSL!_Bz!%n8CwqYYG1S$27;y}6dH z+Ff?J9nvF+@oUpgwpAF?ZaK9`K4u|kIain^GmIA zav!6d+-fz@RtHqw(7mUL+H3D=`YJ0;X79bH58VWFRnYCNO5&z3%0%;^zU(u2>*P=# zq%V6R@V(x*>eU53=Fhyq`v?cVa40K#60c{?xVmA>y8f&jd}Ffq{s)z zh6M|1uITJ7xTKD=$f7I*%S zu%|S>o+&gg>7JahHA|ihe?NXta|ywi1RYy9l9^qh6`%^4FVwqjOokUD`-Q9=+?>R; z2xrIeEqm^=91?d+qr9iyfv*Z?VNaor@iW5{0>~WwS|}W3dyB9r<{}|eF%k*iVHpX( zi0tkTRbpV)2r*w2xf90}IbzxRNxi+wean?5ul9yRA?@rqgAunlqj=8sGwXjLUJw-U1btcrhi9GtsOt|NS#pQS;1y!a5%=vgSA#_w`G+CyKXFm>ZyUlkF{zlT?Ah z`A^ueI&fE&V`#{mKIcLeldC9>lJhHfzN#x^cr&t3JMny#U*Pd){a1h*g^eW3S$_)K z7QQ>%&%%n^i{twzsTyA_83jVY8?p1dj+BF8=7dX-X{TV^*E=ww$jW5~m`!F<4&r`{ zrx?>h^2lkKb z^9tC@@O&@qt6{TUkuDo{1%9GeOPA=?(iQd|u)bO5bCQC+q1ap2C1-afEGI8QcOWX0 zUc%vV{ws;aM;YC2N^eju83yIYTVoBuZsAJWo#;0bCfS@>k7DMLykvucNj^AZ9Z=ULx^v zxpZSOBgQo2O_$ptUerqD0=PvYbcsah3VUo@g0bBQwkikCK$*BwfWI*l5<5y8B`sG;l4RoIimxT;ePRrRg)&o1u)t+%$#h^M6S_nubcsv^qf7)_1y_2j zWWtWMsc+6d(X32dw_FncQKgoMr$zFaX61u?8u_3O82PYw7WvR6@}Wz$j5LW{=n}cmCB2Ja>|F#~RrRF;AxAe+ zU!M9Ja>43J1ut-INn`pL@fPCejH{#Zea##z8hF6oB_V?QidYiBb-y-hl}(y)gA zrsdLUbuSzrU%rXi+?Wxgb2y~Ibew6WQUV=>D8gkj& zz3?n68@y+lUKn{bEeXA`l?`1Y8@i;Y5sW>JV5?XiTUBS8>xEahTsC{X7e=|okS`Bu zG_t9(vY8J|>J42Y8@fa`f>AbtwYHbxoM>3W_(U<&uqr;(tYl<)qojp>%*WtaNaohW z$CYofl4NQ5qVKM?EzJPX!)bzoH?!+4YU!W1MB7p4sY{<_5i zX<6rzC=eGH?R=Y1*fBbffz31=YXvd`ZV?DwA`rSnAc9dKg6+GP$cLMi30J$!%k^HH z*r5`|kTvQknP$_=%A^#S$b>GD30)!+!6*~Ku)h*xHbV#yqa`nOiXPyr02EJkPA$ zVb%lJdc|IZOR#qpONWcAHB0ex<^wo7;n&#$T+hcFzen0U{5Ihi?~hd`&)wNWe0739 zkA=HCd&uX>1pm9)GQ4d5Gizik@LZJ8voTE!`wD(*wbG{858x3_@H;hkK9VeZ0$iMC z+U2Oy3s^fnz*~VQw~WuciIK(WOgtnl<5K}<8#E{K4dw5^LbQN7nCFhljDf`nGiI%+ zWq!#zLkN8iTq)M>DPNlL=Kl=b-jjoUpCLvWiFp`d@G_j1Jq1znV^f^2;hs|SpGsw< zm5)jZ=CAWpK4K&pj4Q=DKgHP1(B6yX>IlTiPjsc;iQuM1UuH{I&$&Ud9fIr#rD>+R z8@#@QQstt)TiACwWguTbiTX9}LLZiN{33tCiaw)08b5zUpKJAuf~b2L!RlvLZWI9D zZ`?`|a)+-uA+b!qS^IZ7)C)o74C^NiQ#!}EJnzTo*jQ)pg53r7Pht0hjaC|)4*Oo% zd`o>0Hs0Wjy2(n|zrpkUufBG|?O8i7Eg)UJ`p(|_@bp+dG>B3$% zDuQ4+))n^pDmGBDV#S6l#{0-5>{P{gn~z}272~^sV2>-dNwHTI<7&OoZC8w|^@6cK zp)2g=SXY*prx+DagpMotLN{44DxL^dl;-G$T9@cBV-#4>tG+m=W_QDaT8cor8cHM`Y({G5@diKQ9~ zuvc!f{ zwIu0Mge|KjI}O*(@aZJ}!vNv<3Jo#8x9ec{0Wo})R+P=UtOPgiYWI2=Y0);NyAAOU zEEsAQ%9RV>OXxX_ck;iOfBhFFL%Fyu!Df34*W~BNv32E{1#G6ppF-1Qc|8p~7xoLV zqp;C@W2_7R1N&ImFTw5#`(@YzElxSD#WSeljURP|3Vyj|^E^t2I79Q~? zaXw!L&*Fq>fD5x9{2tNvkZP+8McneKYl{|a`=LCT=Kipmh5@#GX2C7xLzk2fT{3qS z>;XIrwhAt9EktDWhvm}J#NMJUY2r+xbhz}JxMk+TFlCRnL^`7TyVqv+=>K9&GLEen z>6~h%gT(_Y9lAt1bcu8XqjUtzcUztL`%p`adI^n9>$Jo$c6;ggeQ#>XhwRXTw8S={ zN5C$kG3n?C8*4$a(9%M#=qkqbxjvashN0Pl|1R07w8WSenzJ4_7-LFedfLGUT5I_4 z_@vSjbLqL^mb{yj`LN4t%qNwWnB&uN!}o7U=Ci-y!=crsCzY0%<8#gr7vMD}F<%kG zXG+%btyCqvV8{o$miv3xou@xh*OTzY=o z_2%Ct=Zmwb#(WM*;?ubipQjg2{B<%P&J5B*@pA5*#OLrvd|tkjx4|XKnXR)ipTm>* zL=8>T@;TDb#J8_#5}%_C4JQdS%a3?$M{;_OhEL=6byO0cd_&{vb8tI7CW%je5}#uY z4c}kbJG}Lyk)I`}=Qu;d6>is$9h=0bz|e3~#Jpu(-+;MIqMW-J8lL@U3!y1U;)69r ztZQeuvO!P$Da%>5)a-Qq9`kH0iET!`Fx5%1h+AL|xs>K)YRP5pBRxnB`rq7#MK36I; z@49JTae8FY*y1xs3?4ORM3Mgzaa#VMK}B9kNz&(kp(EYDZ(k^CIpcJs`ww)8*gXpi z`|(4;(2?%l(?GtCbXnn^>qw8qr>e49E6VI(Ub>0ozap^V5-Jp9_79dmdWBqH(*Nixm zieEP9wprR#=_9{G+(g^*4C2T9MnRVz6{4p2^|LfW8Ju78I~jD*BZVpzKgw^sr4hT_ zeENefa)R(nRlejm2sFbiT?o%X{8+x@K+_##AdT`%(2)+quf)eopL8=((ciu+-Y)2+VX z^H5ljJ2iI&h`v#ehP33+K@_eON35JQi$Lz5r1+D z6XO58dbHV$kGa&sW__pOl7?HcUF`j*^`qJPD)7tlusLOQgE=b}Y>Q&M731WEzF{v9 ztz76jSy$NHV=Wj@VF?|-sU}#pVmvA&*b2p-Q|v{>-cgL-qY!?dDaJ2T2zC^D7~yxU zb>V9>iVarmBE{w?7N{Q$&MiCi!EeXWux@g)JQu&FG#GDd4+3L?4}HY1k+)1cTCTQ^ ze?8&*4-My%`NqWwyceSr%UdzN=U`dN9L$*pw;cSSOO7_sB|0L4J%ne$T6)$$Q7UEN zka!fvwPvRBN6ksaZV6z;y0h2#`-lkb3_1n5oFM5aOnh8UB3Q(TF(lq{V@yNTO5_5# zMIv;GMCg*k9)dl9XTe&2w7n%VaV5tRy1j)mY1v`_memq0w#5)NPb!;Qg2gRUOQr)8 znb0LNp-W^U7-b^ZD!AIT=*U!}OxQDyO_(Xf%jDTEK^~24 zQ2s_XZ1Ex+xKtV}LO zT16&wiA?B{`XU(Xi(sp~Xe)c$=4A5Imdm6?&8Q_Z8Es`U#>!-@mC0=6S7bt$$b>GD ziC~n8V5}#Zt*R%NAmpef>d8GVmx&jfr)JB64}rt zZAdUmL@>Idt&&XzLN=wT_{$c{#@{|{iEvsXn}t?3ms#0dZe_#r6xq-vvY|_4BN!zj zSj#mPzi!`qcXP7QUD)_-;O3>%64{(N{I5lfBmS z4z{&qh^-|Wm(&uvq~{fkJ+EM^n2lD+ge|bCp7$3mm&so5d1qPK;E1y6 zd68E$dqEFuWkZ+9hAwGAg0Te&wki|OR>`IU0h{W1?`^Sc_I}Tcw8fA->fIRGU>0g* zGas1L8@fa`bct*Pqih6gZSTVIKJg%Ye2eG$hL{v@jB)3fn(u9s$LaXE@@-7VTZwdq z%`T#wmB>uEMIv;GMCg*1B-jIZ7OaJO(1`<4kU*FSnl|{|(Ncl5sAEYMh>MGMJ|l&J z9ix2=Y^LE@E07s*i$LfSfzTxa5sU&6Y~Q^s@?JkNDJqG7lC33mq(zgtLMxM=u=&E; z%gUq_ZjlLHA``kqCW28Wf_bcXel zhP9Y;T$&%FV`H7Y3pS6&{1i4iyMKco^bW*=SqVDPPpm8K@tdH6MXW3A^-*kqVnY=> zL$R|Jo1)k?ie0DJql*1ju@@D4MKP|*OIqGnjH~j3u|J_J>_yNM2-d;6!rqCBaiw19 zCMkBVVnt~#?0=~qG`m%#(R8aH!M+vGi4(dJz)3S4zws^T_S_-j|4VAn-%aQ_AgUmP zRepDALaWrEO_QG=$C+hAlZD?*twzafOZ@frOo=*z1aIQEXKVY+Lo} z$Jgqi3DW?+W7F)1-;cFDq?)_7Tn+kT@WZ@Rjf;n6$#SFVhccwyA2#D30Gr+YEc|5N zN|(%A=?Z&yTi+~mMXq3c@%y?u(1~w4T!cy77HdnsFihD`S|FLPp#t5aS^ddYI(tV4 zdS9wQQ|+L!*)tXB4+qS|`XVZPz=txwjtX?J%IN=o73dqLJ-t3zKKnynja5(gL^k$^YwfFyw3N(&5SQ9m?i~cc2&vOX62V;B{Xf$+Vd==;=7V%Y}e_|0| z1^O9_M3wX3ERwHCW=J4k1-if@z6vxiwxaP>pyyholjqWWqeXlbXgQY2j|@ASKUo@I z1$sZccG37M&^;~ESwr#FjK)`iuCa)(0{u&i_$ttUw1}?)&Cll0_$tutI8B2o(73u< zB(5wPAuUmX4hvIn#MM8=)Y?YsO}2b`z*n#Z%9+TucycPx!5Ywl#w$R(x3-c%#pZ;g zT`7p{NhhpbH%*XIdAG#v2c%}=2ePRAYhkpx>i`{#i1%vdQN2A~Q8|eDB6QToP1?j2r zMQ06Yaw9@_5-jS`A&;&3M(0lv{GxrOe|Eu~=@*ywx}f`<@_85TvG$p4BRq=q?vKw_ z4$MK1Tr#(3uK^gsn*KZ{zjAprg7GVt{rcGNXGSeBz&>-;!+j<5I0UFd6|o)ng{AXw zjo%D&@rBJ1Dm=dq!Gv(P#(tMG8;{*3UH$strp?5UYwiLmR}WZgaze>EU#v4Zp^1-O zG2xn?XN)}P)(-0zytwT)`D|QHXzO?T^qhRzv448(;OsxFiCjGdUvUGYoY0%^f9L7D zZ;Nz3^$#!nU4Q=T=cnF% z@IyOZJn9Z?;wBO-Ov_Rcpk{qI-q&Ch{0s(vYz z-R73fs3@;2pH&sTw5+mv`kZKGRrSoW@+rLvd-k6)qkQh%>Um{Vmrc2JhJL3M&YpdG z^epVrt1oHF=FON>J+pMm!nqiAsw&Fn^|+|DT6>OFW%bVeZ*`=swCKctD?VbsI z?({ix%4bLd_ly&|{4%s^lhr-rl8F%StN2lV35-FNIE8+y_kg&C=#{)fxqy z*poaK`aF6@<9IBL=7S*atEfGrqVHznHUH?Tp91ZtALmqkw0?aGqumV)>6_4$j6T|} zSgA{gJ4hdG7Vv%jz0L{suh(qPtl7G{W?lMO^%tkt&B;%%-@bVJLbUUhh~M5ZJ|uHe zUF}2vY-p$-k~6t}QFdMJ<9JwJyBh!No>+zdH4Q}zE}uLbr%>gx@cNxK>vC#8ja>5- zdJ@3t%WFwCR>CCEaOVSG46V!)--d_DJ%MHcXeKv2%tSQi@%M8Xx+oxO?qoF=b+iRh ze+4ec z6MsdKF17P(Z(y^c1;Y*5P6P z7MhEclOk%w%QA6d>tZOvDz+&`jO*=l$fHIWb$bp(=p#&VBQ&y5V&1Qf09dr_%M2&f z3*K-qU#>3$S@o=0r4>rY2I%N`*E8udsb=U1d51l>@My-HwA_Y`r7q@f`&)rgVv`L1 zYiPL0z5PtU196O*0M-#y&~l8gGplEm8i`PlvrO0U+hW^&bZ#%)GR>{cp98(y{(cHO@%d-K_`4oS?F=O=HZW)WO6V=_fDN$|bH75m zJ7Spxi}VO%%&h5UbD)!&n@egoqdaLw9RRVSF>85FH8TQ`GGW!tW7TaBfK^DSq`Gwi z#>&E~)Ui=jIv74II~Hw6%hMKZM|iQgSVSGc*_F^iz$tCP87i?Mm-;~A53(wN(>kA^+k;vDsl!Sl7SkAr<5Y*gCVTG%{Zxe;~`*l)ou zguNdMvKQ4A}i(^Xhu^39)Ig2f${5;{`BAwMwKRc0cSQ*uRE78210bJ{@*@ zq<=W>b7ardURrOAFuTB;F$wJ6f@yz?FwoWqCiduCT{XR7gImtSh_^FSzDn zOJmcz-Cee0v|BIp+Be^p_we{#5k`_0;sOiWlribLAAw9-J#XScyr;*U9K^|0zaz~IM!xk!aoGfrAHew??_ld{7wMAI^Xkl;70@Yf&4B)em@7z z^a4X>2Hzll7&yK2Fq+oMG%zKAL|QzXr_^ zW(bCI4&q1e2k~!nO_}vVTyFqg@+7OM)Z!1@xSAfL@`)cJ`zPhl-YtA1bjWZy|rf)p^=b-V!#*FS& zGUlv_W6zpcGI7k9l96LZ5AzQ5GIH4vz1WwQV(jFhzW3qk{kip?Flc04@B;OJ&-#xl z9yMnCIVFQejvO;&(8S?mMwb+iA3tV1-fUb%f3=juM-Le@ethu|usdgLvFAtimL(_# z!O-EOhn1W@X!uCXO&xp!x1^stF%2w7Cg-mqkoipLK>{hX3f!zYXyG;zoo zm=a{-MSfmYB}Vtgn*p8hyaBOW;xa=wqtveY zABiL^z{-9Fo|Co-@(`5YV7~w>rWfNIJ{Oji&nqzzaPo8M^pZJcl~s7B%*=frR5rgu z%IC3rN3JuCAZ)xu89S|ZhD`xkCpOKXOp*d&f-VUy(41r8bnJT_7UZo!cW&@UPF&FYyem6?tNU|btiS6`vr+>_K{xT8 zY4E$gH*5Su=^woD#7~ZG_~Fgh`~=;f!IO7oJ`()=vfDp;a`PR}KmX$XFRr^`tn7je z=ag}8?t)7TZR(1**AMGcSG;R^@#|~eYBRQO)Yfez#;(ly z_?F`lfMur!+j@A8@Yy9Tv-j%rObWQ7HxR!(uNMC~Q_u65)w*!|D^F3ZhW^mE5ZLz%&cYKM@oJRM%u!J zof@WzasLXxZ=*(tS?uN|RSPj2IyLtL_=G$+OX0>rClJb6zq@g!FdcKR)E|xHPLE7l z?KDlku6u-u>n2Q$!W!I(hSBl6ud;x8s+nTqMh!c=G+wWpMRB)?j}?&eip#M6fw?4S zsq(E|c{A%`o|(CeO_Yb@Rn3K~EWL1U={!uAO6Ofzb&&>~W(adJ=kj+Tj@LP%>4b~cBEOV?S#4rK&j)HwC z>|)l26dm7527T-z<+UQn0TSi(jI=p7tw8X3{%Ui0L>C;Z0giftMdJb+vr`LX3-L7Q$>F=Fyy0GHB zy5i^Si#yd7Z^Gxq>xy5kFOJp~Z>}%SWCvB8U01vlADo@gP|dEYu6XzI;&o%|s@K(B zvC;N=8;Z9;G~R|{N(~l82J5SISjJty8C_cKYgGqNo@AcoKfY^TzxKQmn~40{)m2%O zC%FzUyMAgngcwv`TnLX75&7~_>&A_pV8ZiI!s@DHEVqX0LV+FIyj5?ZCR)ykQL^7O zQSOh_alt3gTY~=-dY*R^{&RIH&-*_9qng3>Yy3aWxL(G8Zv5nVTkv1#{;sYaa7hSm z=7=xP3kpVAa9~)9pEF#yV>ivXY1sW{!X_=7Lr#J}4<*aDuZ8Y_1pogr-77iBm$aXS z9nZfP8Jlf)>3$dDxo1N6%QTV0L9lOVPkI{H{qjhh>4LbU8S<*|rhzx&rn*}8S3*3u zF|j0*%>9m)8^=OCe|iNDE|ubio14JW!<|WDyu`Zb*n-9QU*hFUocZCk=RC* zd3f>@2Fm!|ZF-6kwj5YEU{+RW0UpRnzBOMu zZw3||C^#7rpD?6nqyD$mv@nDi;lTRMO>s$!<-p{)%&ari97kkCW&kn5fYm=~L>5xl zGF-l~xCyDmp9o-{xz5R911%?%jn;D`e(&SQd~v15AGSDxuS4IEG>Wwu(SSUIVU|33+a(9!31HALiWP!>)Q4qUn0sA*+*zb@(=V06p zra8~^Vwte#!0rfpE^KaH%!5t3+h89JyAn31301JUqgR@gVe{s8uOV1EkxX4wCNO+Iaqx9`Jl2m1%G+rz#UHv3!pv(hl_GA*G?rX_TR z&1fpvc1sub4n#=74z{kaH$<^vicMDRJjE6(R;$>3iv3ElKPmQxVi_2%B;G9R3VS^i z<6$mI^I*kJSB&>BOW65}U8mR$iany(V~YJ=v6mJ5Qn3cbA{Y%NjtksBLwlHrI{XxQ+e|)tl>z*bH%G(WGSl$US5~7I!*$)p>=b={Dx}BN0>BJuXD^eD>Uzw4b^$bz+`(= za5v(qZK&#!Dx{lw<b-C;e zsBNh3fM7_IW15Z0-hNNLfnG%rKe?GMI!Pv?vD`F2tKLH}lOc3mUJ-tI-bDPDnO}*z zW~+-mfcX9lu5S3{d2IFKdQ@F3!c&d!TZ(ZuD0JLN64z(y;wu7cRi4)qF7X|xu90w^ zV0_P4jOV_DZh^Y4QrFe$N=LYV;5QRLXSj=dG9H+3n#7m;V^`-Dnd!(t8c_2$^z_8Uqvzk2-R0#PPcjg2IkZ!lZ`spe!&Tz`Tn0;Qer4+J1<` z@t9f4i5m8(%o>1O|M-KUKNnRd9hJ z2jE4pK@;QLAPqLp(ciDig1fy{|$Bx>}{~GhmAfj#`aD+7Ty5- zGR*rkU0J3Q(^qA6MzJRp z`=es7DaIL%#LF3tq?roPg7sC5GYi2uvk*ESqZ5qB=ma}KvEGWErq~e0&Q^@4kt8f; z5wk-L)!iDZ3mU5PIgmyhsyjDScfz>rhSE$F0auF)r>@0HnH^f#SF#%9Vx7wkt1dtP}0`u>YPF0rw^u)PV<&3#Jz_S&*)t z4c1Tfe{uyN`8D3K?<#|1-wgr67!J@J%*qeD zZ#aX@f6ePG2N9ETq%{8Rm3d2idu9F--d^2{XklC?S?~GGy6&!WVs|R`d&OQ>jO)h|mg~oKg}v_9mF2P16KnvoEp#VaSJ*RMlT7Z}H#O5U9RuEd z@$+|}oKyjtWm4J><0O@mPRH*f{Cj-2nNGVFs5rr#ZUDA=#OHAV~Nf`SrFm;#ozpaO9(Sn(oGh&%ldJZQd*3-nE zg59PV`xL=8DE6FU)PoRypDVTvtyZw@)@6H*#FMA+=9x+nMGw~2StDuhr&7NNBJbyOH8@V2zLN%$}Iw$3GRoV)JwXgUeXoz zuCu;b-VN3jHha55#~Lbh?yrA>=HE5p{T$UY@tc(K6W;G6RhyaL z%y^|!cP-LYV~!sF9MrZ> zTdNo+c0$J&RiWelk6=ewSJ_x?1QS6_Jh0y*bEO#s< z4(?b8#;LAgMb>4zr+?F=_h(2+|Aav;e$sn$dx*^#H>la(>6=-vh(&sjuirC$GwZcS z7Fs^*{TLGGWWt%CNiSNynOv-c%|2{A3Asu=qe!O9h5pCTC5fF&&Z6u~ws_Pk=BD)xn9ob*aqPI@IQ zUzIVbk)1EMT(`%Q-Xjrb--P}le$xBBfd1kC+^iS%A+c@-O?*4piEo~r_+mHROnmzz zywpv)q;AqBFJyx8g-ozVtt-paQo*(=woU0c-IcHxS=YW)qNd(zV-v5jilGf_{@-d$ zfTtdD+Nzj$f#wnXr)zB1^?0j8!UL|zrmpHi@SzbU>UchFfu@Dn9<$(@@M6hT$$T;l z4Rutx#75JWTkeh0!xyf!5O-rb!u94`WrLIXv@yr5#X!vjk$>mF~$S#>xQCbQ=F;s&uk;}~D5IR{i#gK+3Pag5#AxB#z zT@lKN#=pY1SO83zU8pG*$yQ{ZMcON}*dlEe;n+oUfFeH<0O@j^@3%;%B3#H3<7i%V zfYQ8{guI)CVAszY$0susk0f6%K%^2|(qb5jBWRK$zpvOoWA1!+H!gKCojYMq$lacs z@Z#*?}_5au|{)C)+hZh-T@bo!h!URQu?4dz!vL)2VvPzLaF++bj? zDX^|NbC~zIQ~D+Hro`J#an+qyVt3i?WB7!DJ)zU%o91pJ?KQAZ|DJ}N_Yv%G?jty^ z93M!svJSeBptDqAS7fN5IgNTHdJI4pHzI+qD8+pQHLg)vj)pF-hbKH0U2g;Erm#uF zaQYC<89Ob$HzYn2{yAt|Rmbtk^A1Bj3DSQb2Y%n}g`MJoLYIo)b>MgFi8$UrTIf>o zTZg<3KL?A_wn4J@4octi7&|Tj%_%d4-+8ct(zgofer^_aPA?KViYSQRM0715fu?w_ z&~aQc{3=krrVGaZc*XWIP_FT&C}(U@j{v%Z0_adhT62@@gNU!v3$Z`n`!@_qo9aHR zY|fnSMu(+)Wo2b)?>$zqM_NC^ZzYP9I`%xqvDfs(sTEH}@*<~5J|;nt{3uHha|DBi z4jo@SVM1}7vU!l^f6Eo~n^je36LZ(nHgm15(-gPeo71WZ&}63${9x2VxgWO-YtRW7 z;09~9JN0xMK`T_&88Jr=!?qNBbUi9?S8b&OBo=eS`^Ph*oWfx34V`rX0^w<&+f9< zJ-+cb#Z|fJm3o!nmgnBRM325T`tB)M^Dba_3vX-KHlaqJ+_9#-u6RM&yqV<-Dx(*d zRaH*uS*W)U<2vF(+)3Q459}$`xM5*R{9V6$ExowFY3{|-yH}J~&zot-fRtAN@2i`Y z_w2gieSUFqkBaFNN~c%MxF{NTdvPOeeCq0-65WTF75D7f+o^x6{yDIIQF~o+ykh>| zy(YPDPu0iQnEUqZ>r%5%^W4+rPh;-c6L%8WJaeAG1q14qUyr_x-C58L&3wuHciqrT z?aTNZnlD14Rw91Ap?Uc&JHNyQ%_DN4v$-hy$s%~wEq@+R*WL9SyKagcv6R%_^5Hp= zoS~7Ovm!eN?TqB|H#EGn=EG3+yUWjrKFMrHat3XQZlpkJ%uat0Mf z3U-6w0T2Lv23-FcDfk!+dd`XrFz0_f;Pl%aDflDsmm&qv(~EEa@Y?lzc>NW>-{JRs zq~I=zYF(tu@)d^XE~MtwxA9wz-Wl zXRKhDh_)j>s{O{d`*qJrco zy~>yPyvAhq#K_LfNC6n17;7yU-5b_}z-G-Di zX83&wKg4NDiWxQuj4PT=C>jWuahfDX3O+{}t$q+ezX18O_<_x}k%E7K z>hB2gku4A#@E?(a9g*BiP)T3?3L#+cg7j^5K-MMhS3i&%x&z*<0WR+-WM*@1q~O&^ z0kW`z^%OQrAX4xwWEsUXa$ET_OJH*(x2$k^UCb0R%L`?5Vq|S5+Qto5$^_P%5;55^ zu0Mg`oEQ>`+r9^FLi>r-uEXWF%dg>#&orZ1Mkyzfv)H5FV8NzHj*Y}Lsa&K%+D^`( z81jKOU~`4|cfAE)X>g`7Eyk;kXB!t=+TxfzvwbaQgi_1Uu1x!~d>6-z51SV&5m+|U zyo_A6m7xMOZe^4&Yr{rUr=(qJMKH~4U8DdhM}z8OT3K8{Z#HeLR?@NK4f>dNW!ji& zR%~8qR;GC+HZ7?{Y+9B9lCl??76l&3T}k04wXO%~SHRZA$dRrlT9+%H_y)#={`(u) zgRE!c3;@S+C_#S|@adDlG;aPlR>RJPr_`asDPxfgh8&1j?}{$l$FF^MVkPB#laLLqB+eef^} zVe8>9W--@oj`bJLeH%rh*Q7*M?6; z=`73Jh4tzDur3!&Bah`o5kbhChr9CP0&^ROr9arja%ct<$6WL>&v{6^XhI!@>~TZR zMd&m4BXsYvj4&4w_T*ZNz3lGnb4*Z1w-eFPgEHgw`CK@`nr2TE7nkaHqnfaY821Xe z-Z9TOP~#I98qZtdx!rh{$9oE=AHuT|1;|^I9jBYkb2lV~oKYb3_TEmb@t!p|`P-xj zcQRON0(3MCZpZTv&GWJ5`3^ku92;NY$?$e%cw5?O-T`TG$@TL#0Tq=SQ7%QNn&%XG z8)iJKgY))hROEY^N6_%=kmgQe#iLbn7ka77;(npG1+O|vaoP+-Ri~=8ScQs*>;XBYgQ)Vw1|8z}*OCK{o&CvROE`4lq^>OLzoS44w;vQ+a zNL+S$qlzP?$XIc_7ABc9>*@gG*TLjGiF4ZG_9olp+%Z1S%pcQyB^l#&*Y}fHR{-TA zUr?-+_faNRsjf+}W-K`}Z9MaXhS1sP>`R(culo##9Y(S&-2&4mO)}4v*pVj%K5F-o6Be@cpTpA^qBz+FGD8=d=+Z;oyp1XhSAZ+&9~Wg(hQmt^ zG6iUAc6_X^YH=3%EVy{y7a>=*_yrs8X7HJXd}O&~ZiuXMuZXOYQpO6EW5VSJ zSI3N+_StD!Ss5uyhZRFo_N}y&LQ**xUjnvwvWv6G-l?M^V%a5{RT{z#w&`$Hu*j@c%NlOmCn?Bi=He-Iy zriwgP;90(Po199PZab686hq9C*O9c$wCv1CV$vA&NE1zR=gcVoX8qXTcTC89+LB*@ z?LldYJel-t6E0cUY_)X>eooko?_ul5_>xE9rA5p~su8%zOe=#&;PJ*Ug?N@83$`38 z4@t}l>(Q|$s6SM?2W5lSqh&XWkWw&&uVe&iE&{<$Fn`fC+GjCnYv)^o- ztSQe2jh|mnUE@exD`miSt%07^5Ri9jyG(ci6Y6) zsJ$xfEJ!8g5YB$Cotfx&HX|Bq$1?MLj!7AX{jjQur3n`#KJeYlAsob^Oz z_P3{9>-|oL@aIf)q0n*Ovq|lZ-S)<~D3dZAuB~o*2({gjD4^)T&nFgzqxm@#)VF=v@7%v2tbB9$!NxyCQWIJC?RZ>fgqt4z{@ zhv^YE34z1(GEVG*hw0fVgw2-uUV@(!HnZ5##3#cLl?l0&?j;%r`q`a1T4A4X&cRVDS^#( zt}|fs+|^8r7kF}qTQ}GffOUs`G3=hOISs>tQ0#tmkT^XZV|fpN-5GpNfn5muRM_M=Zg~RZZbKG>vIc~bb=GITamRY*6xj0!cwgRF1g>_|l_bK+WVt-KVuZq2= z7}O{Ymn;wG%q>6aH%S~vD|Uiny%nRPuFwrrY_ekKDaQ9Jp&bq?hv5Fn97(YEHbX4Azu)GOQurn2#q}aKN zEl_NcVpl6xuh^Z6-L2Rf#hy{@CB^5g<`)|>?y^bQ|v{>UQ_HZioLJc4#hIi>r48wtSjsdS8SAG=O{K+u`##u@@A3SFyhAyHBxSDfWqCpDBiw zH=7phUKv-|>!8>{ik+Yszx~J5hrJPsjZtj5VmB&wyJ9O9`=w$JD)u|YUQjGE;?kFG zU67SxQN>PHtVppd6MbZSJ=x@EKjj+iWMq$hGHWX zyH+t?!YnfVkzzkq>^{YQrP#BI{a&%ZD)ydY-LT&(X)d&`Fb>b7arr4p_^OCgi)5pTEzhWmTHbJq;itSQtw_+3OU$5DoS+lj- zV`=pp>nG%N8Is*~)1>7ObEaQc%Wd1qU3WfJgqmDGB-Bp z#`=fV%;~m-lQduNl$t%6We=;h^camz>S`o6?idYMI+Bmka3un=`MSqwxSX&LPN*^E zfhW|McsWDEn43OBW6C4`01fl_?>|8E|L+O49XO%3QBSCuR`ku;G;}36BKXbOw13Cp z&;J`|)7Z>-Hf{NsA{<34OgM^`(}JUD-0D9b6|=3mNLXB#06WfLJVqd{+p*Ljz7ML4 z-)PF$8Cb_dT7r+FQH3+{ zDB2+GF(4YFzxN8J5CapAqA|=M_z!}89sI?_9YrfyP*!zO$-?pqtjab%ljgQbIHxEw z;c{`_Og{V4#XPskI10C;la43GnG7-h@h?s&#Ejd6vufjl&#G~^7i*hd4-L2wd@?)px|?8X{ZG(AGg!|A?ghF_mfXlaX;ZR~!;jI&Y;dC!=nr8tMS(**YO#Wfp#JBcFa&cFr6-#>>Y z%mUA$?ZkS1%3biCWDBltcgQW7Mb`_aCE>Qo8T#?~Kw%pF# zYWz~|g2z^pZ{RLC(-fapx7Wj3w%qvrC@Dhjxcu7qrP>9LEn|c@M--TmWhQL$HVQK$ z$7zIb@-Fz|g_L^}yWpP~*2!DGw*y~jM4wzN%<7MgU#ea3#fzHV1?SB73lq7&3(ggK z*QA-Z*NwlwcjjbGc}_R9$-926mp_b4T;dLB+Tx)QNmIMvcbZs}MZy&2r-+r+ZG`bl zwF|!ZkY;zm`HFFmiTobZ#K`nW!_?meuQUGHTE(15Rsi2GMdDaqa(ph;F8Gpe%^zgr zHSxTDpRJ3vqqpgQ{ex^b8Gpa9Tq9=ewT3p;F8Gp?CU(JDPo%#*4F}o$UGPOFx-T(s zuTx>TC|4rNinu5f>j2Kq9o6(MIA7`{))&&;E;#p@sPdfdy_pmvYh8a6W2#;7CGDC% ztj5BZQ<#_OE_hcHqrVF-ht85~CM(LDhBmo9u&o?wQkI|M2t>_c&F_MXEGp9a#~oJ7 zH$#WN3%=OI;-?_KYQAUuk}C&O*VT@W!Mor!A=6x&-32c*F{IuFmmFM|-o?u|`}mCc z4>nb93b86hDp|UDCY341p(TG~H=Ak~Tuw12ci$_(_G1%emMNO#!)gzMZSXEQHQeKm z<2YfnW!{|N=bFU|_^q~n6n64qtfj@wN2uQ1q z57YgOU#elc<~{Na9H!qh#pS2f$%nnsABkD~w;NVR~tK zv%@r(`F5Ge{ljXP8m9g*{bGv5tv~|KO_4a3*K*^RYM8EF+WcX)1I*iie^{;FJo|^$ z{$^uHoD?(mErvGLFkSmt6T>v?iA?{mYjjv`lZh_%VYL_HqD&s9YcFqlnC9fb#p;IX z+f0n9537CK#F%QBu06l`!)o`K82rO(G4t#X)1@Yc;KORYjbCzmU|Xp)eyN7(Ws900 zrkyO}534OPFKPZT{dz(QTx(r{6r5pb{g&)nD^pizU-p8B>18FRxi&jYuQRcy9;RIm z;t#9!G%@>!)jFg|CHoXA6Y>>;sZ3H^T4si~RKqmSSnv!~V#`{DTbhdHu#IKs-2 zHM-=;8eL(2aFpLj2lgH73gatz4*Q8>k1F~&MD zP_ZJ#c)6~mZ=zynE5_Ft;l~db3f=b=<5wmGyIZk)6?;ap-zoOCVt-ZaW5sweukdSw zd7#AG*1B+fM6u%(<6EB4@%2W+4pD5FViOdbtXP#|3l&?c*fol+RO~Lro>c5<#rSDc zNz2QMy{XvSihZdVKX)o=&O!~7uo3GDdxt8<&yxuqUq*!P1jS}3cA;WdDORHxYqNxX zQZddo1^csN5sVjtb+E3m$4Rh_SFvG=jZloo(}a%4)96ASSB%Hg1bb64o=z9+3&sAW zSVwe1!tW643VY`%R-)L&im^)*ev1_2IbXrPr`WBE{aUd{75hlBe<-#;Iz35Cu62dI zE{b(mY@TB5?IqqT72|j(*!7Ctq}VSMyHBz8it#|3gv~^cBWcODE*#}kj7MvQu0XMF ziVaol48>{`yIQgDDR!%3k1ECkZ4$@liv3fuc397s^zCn5kdW)Yc9mlF zihWzLpDA{aVrv!KpxAym^d)I&XI)|MV8sqotczmZ6)RS3xMI^4D^=`giru5w2F0FJ z>@~&yqS*V2?NAH~Z#K!|3CKL1U`x?>-(=xhY&g~osh7~XjoK4#Xz$TijWXM zc8G!?5JLzO1%g>vR4}0vpeZ7|g5rpZBaSGjh^U}p5fD)j7(`_h6cq(!RiYxizjJQY z>9ty(8RmK4&;M_I(z&<3cfWP+y{EQQ!nz0>CTzH{M}$2l>=j{agncM%w=f4D7*l;! z-SFYDU|~&#WeLj>Hd$DSur>Xj7gzXfzN7zwe$AvY;17pTr)ASHQ2|qJQjK zx$rQ&_6_!3-i7-KZglTHd$w%1&U@wEFBC=Dcj__a>rWt1nT*?T$f1vmwx4_hw|KSF z&+4yH;q71J>^--G=^K%5!$F6)j6%HS6r!slDfc$|dg?vTuQpdY+o1Ds55gcFU6v@U zsdH!O&J%j)6Va;3qc!!aRBXp+J;|nbwncjv(mj2Azji{>J(|&tsr~&&DASjo!?+!!bPtr2s`wKIA>7@?)-heNeeW+;2cYrq|l*UOC!e~o{ zzm?xp9dsAIZP15BC`~KGT@AMYBU5easg8o2yT{~=EzD%o(6DpUA>lA$*kBGAriR95 z=kW6yWRZi!s3oVI6GfM?YQx`*_wBYU!$1x-fIdH{X*b#^P90=)7w_M0i_zMHUCgr| zo1>^2WNEmXX4>|ZYVaWEVpm6*-)pCS`iP53(XPkkj~e)nJMG5eM`zEd4yUKbPKc?^ z_p}ET0b^So)fh$76#%@}1_R-+J3k_4Tn_%Bi?T+Hz{lDP$gI3-9DQ+_w&%3lKH@^^BaS6)W4IP>F99V}ltAWfuC;0o^$d$RGzY7Dt&431 zD08Ov6%SX{M(W|wSz~ihL0<#k=PVlF%GYJmNE$12)kR4tHQYuMqG1H6KWLJL<7o{7S5n z$?Dp$gz;Q~DjJ3HE3c>E>BbG?5RK;0Ztz}>-%SRei>rODu>UCBu5fWzr??N?rEu?t z`!w7D!*z6_TJ{u;O>&Tqhthl{zan8acO z+`q!z47aDTPseI2_D9400Im*q7hDq3-Efz}-2?YExF5sa2p7*D6_bphtm03MeY!SB z`^VrOf=k!szJyy7?f(WYU03@a?hv@g;FA57AK+%geHSi?I_=Z-GW20F&4$!YI!5*J zQ&&aFr>=^UPkn1!v4uuF2Wx_gq5n9oL!;hN41HoSlxnc|g#Akx+F-;xDGc>7SRJ%Z z}g?t7e+SWRlGNaZ5Q^Tu+zfm z;XqZc9X+bjRyBMM?Mh*dgxx5Nu8*p;w+KrU)<+m!A64Sh0!%m6_2d)sk%%MHeHx5jGmHI@tzU(p0E#u zeIkrr&{bu8CyegmD)zfD8zwEq5)5CQR#R9q!or_{t*ryC@(2Xp?<`DDgBfdY*|DQ|kh<)|aXJrB zrvTVH?c39P#6op1d(Tzc1%j$)ILmgsO52k+%KfvKqw1+R^{PY~*P7JW#ojXQ4AlBg zvEH&+_8>5xJ@vf{qv2V+wd@QcQ*E}EofDrEL5d|AK5tna_`D122_q>#{uvOWXmF6X3Q-mFZ0@L+{!ZQLjXnwA8S-^L8Qn!si)}v+XCXas5)#Ht zDjmm$_$Bc_76 z{;?LJBqlVU)3yyG;zp=O6qjb$2eIEa=&5o_b0fl*!zCp^Z6$Z-jLpfXk31QQbxuLJ z^AA%GT!O@OMnL$a`)@;?P(6ov z?NSY2k-lm`Wiqz4tgq8YQDFCI%(x(ftR#0T;&L0^D=y+4b?!jt3S)V{4cCv(4OH1x zAqXA#Lo4(>7<_pvI9FpB(xI#+F^$6)92X*O)_`(t&MNl(Ir(`lf@5NEm@&!9tS@G8 zM2s&pqN!MBq67SYq+HUE6ibp*bMqb3|Dj@e5SjTYmUW>-(m^177})>#lYUA4PRFE{ z-!Z8}96hJFf4|nF5cHD@3G7Esg`T0_sHOS$8<}vSsm2##^pp9e_(f);;nLXa2AAqQ z%itq5rMKP#Hx2Awxc%UcfeS{$Q9K$hgr@ieTqwuIzrlR~F1|9aJqVXfpiG8)J=`g9 z+rcfyUq`r8;ob$e46X;R7cL1H%4a?BO5~;VK=LU)kbLUHoQloGzG6=pzBpc$6nk0N zYZC8WVWbDDct?aC6LwA*0v~-oWuHkcNorI+eyH{AAFnS_WrClU!9cFXI$Y2lo z99on;x(Z&husPzKmsNMgRx@^^j9o`Zd~;`9v)mDHWJTL(yxO&nBXhC}o28`SM6p;A z|Ig;3^7xn~tq*~l|EKFvA;h7N<^^s>99|1hLBxS<25tTyF{MSqZX+Wd7^7OwC`pJzAIejw;Iy<5^UsG)Y3(+8vV`(!_uJQq9h?sW5r;mIXXaz|F;qIY#LYLY zVp3zAE(YgAjkeo%pvXJnqs{7Ls5I7b<4m)s?C2Ak4~N+3gLrB&qB5yn|Ncih>11DR z$vA1It&!SA4NcOT>=LELf%;j{{;uLg+YJ;XNGm=o8z*Lt7q-qg0bcZk1`$j5? z6Gi8~>Z_G%ZqCFPEsOB&O1|QdnKgRcs4V)BB`mxLUVv4Mt#29O$`Y5nc9$7OYwDPZ zTyX6yw{Q~rB?pGPvh(up&CTi95}%XHDjGdHKW7YlevvpBXyTYL9aGw+v`rbAl9Mtb zB|Bw!N>)nql$4Y90(+a~+AKl-+2tClH#-`0%d zZ)+~w3G2f~NBU0^glLM`VKV|v#}WE%&2<<{zXiqXXz^{$*XbDhZ5%J?+nSRh=WZO; zRfcraz)lYHZOv}i!%j2ebm*%xYy^1<_wCAZIKetThcG$z7Sx@-33 zS`VnmwUJT0E%aNKW0{A3vywE4aNnkE3|SBNZOXCC!+)EyKH5OrD%7tVT$)8op*GRY zLYjR~iFts&1}o3uv4FjoOAQK)xx7LR((4LR&UZ`LARqEoj-i z#s69X(nTor(n(RPOD98;mDIHLrIVisnaj~=EyqG#;U;xG2Ik|uSi|Ug!vC%Bk>0K! zD>+sNwRsAaFg`w-?$mq5XAIDbVh7@`!#P|e^p+oydk=~XFmF*%FvaqPKT!yKIa|w) zflwt(d3-?>8XHbdWV_8Zr-jW&CQeS=<3Jh9&_`xbAf8G2>n z9u?EuZM8;;gd8O6Qt?Y=_a?oC~;Z#|o}TpzT;$ZTuk zKK;JsT%W`}RF7>cfqwrHJ$07*7k#_l@0h;Ry=%jvc-M-LV)%?WS!GkW(wu9yA`*GwO{7nRFgr*C&HJH>sp z(f+fy>uPjU*F|UVUhD0%%BWS>MTrBK*t@Rv!n4OaaEV@Nh}_5exFsY*=iGfO{l%zK z@4nxgdXB`XGWZ}Juy?BTcG{oV@0_>a0r#K-dcU>qUFhcRVZ|tQt-jUU9d$gLwN@Xr z&d7|#Xf25mRjA(*pBPo@sY{d?oeL{Qm1bu_jLxB!;l${GeXIUU;=pt66YfvFUH7{y zyaNve2$G&z5%;0D>pH#b(z9QA`>dr}d7n6g5rkpab!prTVtLbIMzIY77I7n@L+;*=W5qm`IX$SRRWQs{Un3!?cz9sQvFYq>R#$kPzlmYEA;NG&K@$VwMiA6m@&(~!J9TCF=Mqi zW0t;4?=j204>j9~o{RIQMeD!l`wao?W_bYbTLsDJw4Y?`gx+s8lJ`3xBN5#bM?**T zWZZ>g^Math(-(yt?jB9C!dtA~)K-AL4{e2CjBPtT6VZchE0i=nt&*rmfb~=I90M zFfsJtA*lB_2Ej_3lbAu%6Wo2?j0Jke5qFOT)WzN&N6<6nEF@{i^iBF52lY)-xOD1a z>Qo%CV|1MMxbHux4?e8#^gh9&c^WhAp;*_7vvt%lh}*j1$2wk&zDh_s#@|W3`q#ueOEjs~yx=+Y&R*pm#HNP;YJ12k*d)a@y!6)on&E(QJS*R*7EXk)wBC z6t1tRLY)?=o=V*3?zD(zE-Vx@e_dQ(@eGf?+UD!4ZN9$Z`f^|Gz@&_^&V6OSK;5)F zZi}}^gd`TYC0ey~jDTua+ieETg_!N`1A=-D8=aQR&|0?SUy>Nfml5?Hu*h zu5f*|m-=c~Vg??^_Gav*zS^Y^-fPuY%c-wc`1cjfOd(4-RjAWaUtcZ7?@w&(O0{CeYMNiS6pB2tG$7JwIyz+H*JNt$8yinV$X}Db75+y@$M>{`!k*@8CvSo z#8iO(>cronekmpF@dwF2Vx;ReoN|1 z<})YaF?jD(3PbKs6O$QTDSLAtL=1Zgg`gDp6X#NFFLQk^)zrP1;zUs0W^x<0d#7@{ zww`^8-Ni(W(rEpCnW)(o%(bcwrat#3*LNzlmzQI%Mc5TtX`WL#ex-LNw~gBwMl4k8 zw)(dWsvc8oZSU=3RMb0-8}+wR@;}TCdbk*s^DiXvkx~!{-ZTn9lX#!hz+%ij4^tp% zf~DRrrN;8zyBI@$MlrfG+`%rTLxF?M;U^ONm12pVOHi${p;{qUq)KRo)40M9Q&sgp zs3dENs+z1Q7Ar-u6cQ9cQ7ra$FV$y8t~OSCt~gg48lzEh{ZVef9{tI4R6T#y5d(WV z*ZK8I>g3tf3Vn8^>SQ@7NqqDib@CSPbP7Qy^FG?G#?Qz4Dhfya!zh(AE75rtdga`6 z)Z0)kODGa)mrUG?iR*KzN)gn|nW{D3sT2?AEKjk!n5e(V6Qv_+RDCX2)fD;rEA^=a zE?)iQ_V`PnamJ?F;-`d8r#9*Dqp#o^XEg2#I-`l(q(7+vdS`QuXKSdTcRIIbgHlP) zeq~M(iH}B8{Wp21Q!MOJI%XH6qt2jDr-!R-G&lxL35AQYI+rMvKvQ3x%BdfrA}>m7 zoyv`xN%8fWR9%$(G%>R=x~ajIaLf{pb0Tprmw<6bO%0>Xno63TblDToBz2=%J^`K2 z4cg-MaL6_&w@g^IeT)iY?N$|}PF#E{oG7@D(G2gM%Jtvmok__s;!r19jZD34{)32# zCDcPH66ezh@-lp+2>PMLUTQ?QK7RlH}eYrI@5UB~Z2 zgIe8acBYn?Dk1L~t3$tNx3NrIl)e+??M|BXRI0o5n`)G)AW9QyE$8M1sfk_>)f_6& zTRcEsrJ>=~sfD^8ya1rTNrvYe%YcWMfqh=y*XPp;<<=>T6-k};MVItYN~lPSSZG4E zZzWVXBov-FpJFSqLUs4J-{e$}@t6s(WAem=8CFeHK239GNE-}2z-U8>YJ;Jk^B$&h zv_a<;*{%E+r&946ZLH8ZDpY6RQQ>yUQSr5sm3K9Od^%|y>F=-7;GhG;1K6Vu3?C$& z=2!oz1`-W|NybAVP*Ztd&nSi#)1%a_^R$cM;q6iEO)JHDC7%rGizcFkFe>Z(2f=yB z!A;C4h2qMHjsz!pj3QWQusk!-k>IiIcO-%O@XixN85AUI6JS@01AL1&QIw_#u_j=6UpGZUD)dzW4@HC}sMErH~9_JG0 zM+4FUpg=kRwC~pGzt!2oqGIaAFhijfoO++a)oH_gLe%@5V2v(pGBCf zL+~jCuK>I*QB1xnf|D*@C)DadrxP5>@{HmTpVOO*7@q}rQ;qYAsZ>>8?{iy3{LPke z?{jN>vXApII>+#+9;fDbHpK^>X*`eTQuWv960vb1SiSG8t`r+DKjS%cJlpU7AamHA zN9a;B-jd!#&zM|;UyMfYfL@MYlGYyo>1J<|)?3&ec-BRQ=D?>yi{NX>@#ymTPxzJM zXKwVg4PDhXAIu@sI`rTn#ihsB2M2|x<0+IX9I8s968+Q9LwGbENTZGN$p{KRjc~Ix zdYq%;M0(G!2X`I$x6=(*)J2*D%a^!}fEfQz0lr-!ZS345|7 zMeo+tgpZn{HXAyyGr!hGFH5QnaNE}}J=FuHVk6VsD!pn9F_oUWiYh=aZ`%C7=~!J$ zO`v0o2Z^xtt7SerPp>P}OUq^j`)~=3r2w<<%>w8#IjSH%r;Nwt`P-0q=A0`}w+~!_ zVf|GAZZFjE`{Xg*|92*o%%aE9uRxB~V5N&*y`&zZO_?p8z>FT;re31w7U(%+GHF)R zFE4t2z*(;($7%lyWk-(`nAvd^u}@DiQLTfMay6n#(wy>?kix{DxmuwWabGeg1fJ7@w-lY{oop#-M5jG*5afgM=`n>rep$-qFJ?naJm{? z4a$pJN>6r?gwmnFTPiZNxEi$|azdxxXVFb&pr=4>Ql>8dZs)rY%+9lsd z5TfrRkHMYJs47-+q#pEa$Za#_XfJ1{Wb*Q0IkJ~L?~ICZR}|NS9Q8#B1~G}@PU7fdy52whVn^f_lF1r56E~=>oBrq z&I~QNKI(OQv#Va=>=uM%rzR+mGlFc;d_9?U*h6OG-&rQvl1@Oziny?Eq&V=6^&UYxB+I4uX5_k z0~)ZAnKEA*GKF4V`iRq>?5m(@@}ZMPcYiMDq>sZigwIOBVrH%YF(aFU^qxc5gIli@ z-{bUOeU!xlx+`^_g`$}AHXH>nwX8D@X zhLb8|y6U(EPSnjg{8cW_6n*-_uZFKx2N!1?m%l`q8|gh`vP3|=Xb#MV%sO*+A)~#D z=a@4(*6DCK?U#iwZ`##RU;=y9*Sz&CvCX9VR62dSSJTo1dhj}WiW5Q`Tm%oJ#A&fk zJ8LxlJ!GmIv7EFCCk>U-vO~@)vCg>5f-7iB=@(p?Kq)2TjilFyt&F|w6=yvd)iZ}t zpeFhnC#@HfR2`bKN1gE@%a+*=WjeW$92%;_OwKNF5+D{7jN;&`D`4cFT>eXy~5`73|slK2rz z)FL?&l-+)2Gr1f5rA*E9(>6G3jd$AX23DFT7d3gU;nZ#L-mOo2AOoE=QTfuSgJCwb z4ZSRaGv(mptU7*rHD{fmQRkb>$XX~2?{IPET=qM&ByJQPAZnEQ;L#N!MR23)P22B` zvOGunjI&c3hyQU@wVU>mvzo(M#pR6RuNQ>tW^oX*H8J5yAKvy^paW{UVgjyH&lxFST? zoR&@^9$m%hsOpU3X-Q3Lfl}U`)e1Uq_f@?gv%2A{?wTvQM9pXwL8AY`SvL)k=xaE;THGj8 zqFXStlIR&Yfw7z%t8!8$(f)_c7;iY^xXf8K+F9i?XH?L@^NGWKT+Q(T{XCkPI;{#7 z>gg|r5o%M{c!iT%srA#Jh#;(sIH?j=bFC|20cygvGllgbj+Yr;3aU&mbXJcGI4cSi zQ!=4qPR8a4BZJX&C67i}h<2Ue4LSWchf))MMK@4Jn=-SKQE$^w8C6!c)T}#>Dx&qN z{(}8{v^g)(G!e_WTFdEd4!4q1Z&r|;nufhdi&RB6sQ$2h9~WuPz8RclpsWsKW+kiM zlnAow=A>4#I^(yCk<~>k?+*mX>QZJ?LPjVr2=!-t5p!tBWhn}jRWj2|2J=a>LT0QgGoIl~9xV4yroeUNa5agW(vZsR1wN$yBCKYHS&jL+Vp8ydHRY== zrw+V6)r6Tvch=L-I_;JR_H5+gxi7*rwTF`iPD!6L3)RWEE0gq<5zhQqa?%?uyYf*E zf1Zz=*_F>QdopBTsjhr@aF{c3vmXzUaRJy-@m~l(Vzw}3uyO6LdiXl4(b2qmq|xzk zwIG@FpV!ZEk!qZpqoW#UXEn!_Z;Cv}wdEW)bHk{yw8D2`_IUVyiZ6%aWO;++aZakP zHJW`F%dA5{-~GTcSP@bL_g($+5fNlCi?g%3{#f2Scqo{2Tt`k9ILCEkW+i~-Nf87v ziIcVrX#oq9YxeO77bm}RkpKj)R6j7YxHwsFHim-bpnQ#!!tN5zcFf7UIIStJ|bl6uid!1VpI@8Ra75ReY6i%&FW>YlhFbkc1`6xG@-QO95CD#8^knfzI zOyFx;C7-fTqiDOs$c`Fn%IfPJ&+3BZ?52Uz;5*5m%ju2;oD#)w{*6UYsmuu+uO2hA zSq(X!#RbcH4}b2AN)Bw6?~2~%oSpSGqWki*OeCF)_Xvqr2lCPXJPkAa6%-)SNCb4$XAy}7!PRenvY2&l{fW-o@XOw63` zo%KhBOa(q6d7V=~#s|@yopF4#&Hvhvd5DrZgBH@y z)Lsv>wgJ^#$xK}eZ4i8=C1%cT&gh!XXk2W;7e8_Rx_Yokn^VbP&gNRKZ^#*I^qj$g zBhY8@xhJO!yuL}Ff1n38NPqQjJIiLw9NaW>I_p$-##|9x8MEzdh6y*PNZ?5#XmfI= zYFN{ep)pm1Re{=EkiT-PX7Bm+B8c%wE^Cu?FJ(v8l{M{6&d&eCa;o0*Mmg&j7dvBu zW^kVz_v7R<1LU|PGiy0M!r>O{Pt?5C5#;!1md}L&a=e7IOAZi_mzXIz_U|NaRr0*C z&M3?CxI#{1YCTBLJ%#5NB(xT@zDw2vUtI%hp0K%^UUc2@?7 zbSq|7B0ay-85N|F_?GVTT!fWK&tDC#_zy+84d?N}S4_=&SV7R!Kn*Z&gdDZcumJ3oki zEXG_hDA#VBtF@qh%i&gny71K?LG{1HX%_ip^nF|;&jcuP31=B7tS>TCpM3S7iMa2R z7mkY{tm8SUm9Q>saWTUB8p~Lqu)f9YnegJ!aADOjmtsswb@^4vzct3_{x!n9`V;4& z&Mi!7xRRwPP+0eIyu$F(P-DRcXKc-&d6kYjuK_p&TRFA*_H#XaK7nqF-i5#{{Kz%^ zY~hwKrXm719yQ8aLYn*dEAnXvcL-d3dZn12$Hh~}#ncMQtE#rv@WpBC z44*^$R@hNtzX`h_>>At#q+H^(>kOX*->fm2&j>6%S*qfZxqtFGw28tV6gETHEMa8D zTBTho43A_Oj6M;h@@pXMDq-}=1(o(LVUG%JGu$P3r zBJ4Y1KM1p7B&jm!u`E@;TZGYvlN6&T9#p)6!sZHFDC}8b&kH*!?65HUPO{4HO2g;S zZWQJgHcnWfuu@?&gl!Z?9|cu)-Y4u+VbyV0P?cN5@Hw=$7vm?czQS{gow z)>qhV!bS)iCG2Toe;2k!*qg#m3j0YI9tJYXt!DV}X;EQ#_<}6xt<-+C)+a_#>up`2b2|Fi@PD`nW99kR07pJus)lDBJ3_F!Y&uqU)TU)j|h8A*gu5P6%$qGuZ4Xl zEE(rgs@%qg&!M#x)>c?IVLgRS6E;)WW5WI>Y`3s|!oCsqy)ZgCR&{A&_^?(8>nLo9 zu)BmkD(rD#D}}u(Y?CljtyRCA7Z!!{0mV`cU!2xO*Z^UJh0PVVP}mM(yM!GSc39XM zVU@zVLyJ{?(A)4iv|+-A3tKGg31NGM?H6`L*fC*O<8q2Bqp9J;34*W=!it1V66O_F zF6;?mPYK&E?0~R%oF}PrlMElmzOW|3GKFOedra8hguNu}6=B~A`$1S^oL;DMn;1UG zm9UP&CJ1{#*rUQ87xsd%mBPLg_JgqBh1u}3BGtg5wKaUusf85?n;>kuFkRS2VOxZK zDeN0zKMVU+SaZC1srsOm;d5x|!fq8dSy+j%wZhg3+aYY1Fb7`gRAp2*d=BjjVGV^1 z5;j!W7-9DbD-l*EY@M(QVP}L@3X8?5q^gV4@HwnZ6joPQhOmLc?iO~hu&0InUDz67ZwlKk>_cHusEDddjNx-=wS?6Z z)>K$CVI72}3Y#QsvarR%o)Gq;u$P4$5q3=2Ibm9|sww6n!xyJ@5LP5?k}$8Za$#GA zy)W!DVP6RQP1prtts9tq^;g5^(7FrjEo_*u;lh>(TPo~d!VU>LDeNa_cHuP0aja3?JquVfBPH71m5x zj<8%|lZBNCdrjCI!rl}1fv~FAnstdYeE5i_utvge5tb(GeqmFD%@g*Bu)hoYhp>Q?oAD8a{{CPT0-D3WZG+wo=%u!Zr!pD(qunp9!mZomp;O!{^Wr3Og(;yrJO? zeQ11uq2VX~2Zn~(=x~N%h&aURaI$H2xKyL)9~=0hKI>AAlXa))9|pJ zZEcfT%s&ke2cBE7iD5SING4UyuVnmbco@%@{b_g@#!3G)Jd6heVYn5egRHIkO!EF| zco@sepN5D3G&~Hm&wm;o4*0~$f7|fzow#s}JHvRse-s{q!2N3Y$ndaYW$@v?7+5s^ z|Ae2q)C>Csh)a=$}5=1aWpyc(4iL-njJMF31Ei z)d}}bwMlTN;ZYv7`I#WjluyK8ge~IXczfahsx9IywndDGaM-4^ru7h8#F=QIGTN#t zh)4L0O&L4JV_T^FrLjf4B>1%yI=ZyAw9)?wD9C5(iyjX*4Tbu@IG|oZDJhCzi-z;X9wut{3!PMt&PHOe4eeuTNqll-=czcuo2ihWjhnccP9C8$E7tfAhjCi(@ z9UVpg*X7ikBU9H#HbzWO-o&Ikjy~F9OBN`*VBFx*hw93*}vkLtWwAxainT5R%d+G5A#)!vKWwm5H;Aoo8 zP?Be^p~pDts1}sSv zm{}Sl9u>hDaW*FnG}bYanWZt}R)1)WxFavR${?O8QEfR>brA8w29L>}94~aL;X&e> zeoq9`t%vydFOnlcFc6i!ka9Q$!)w!p#$u2RXaI7s~Tl$~tqg zrb=)($5Yl1{LPr~0JTrM{bGy}4`x*(&=_$RGb>XaGaiW`(au=v4`m~e<`$CZ>dfZw zJmSB)E6rs_^-x2vO2m|**WX!m0*w(LV`gmup@2)YGV(ejJ%U8P$yo;)BW}al1sZrw zWo9MOGhjl=(im}VPO2o@|F9{^n2s}!KQ=~O!qprfFmpV}%+eU~`Y=Lm&TAVvsg+s} zJI2<+x}1|LVKrA14+~JBHO1K+&&t5-^wP-2h^MnM6ey34#JEU;H{|@^JP~PI zEmTJT%FIeey?+grQGZJv#gt(fW5jhhS8F+alEba!)O%l$ocdepP(_9sBhKb517&qA zGb>s3c8nmaX`IwbR=uzv{l~JpoaOz209jqd%+eU~cM)XuN5A0{I%gRA>Ze2AkDUob^KlW5l2GHSiSfbMq+v#LVJCSn{m3VJzU7 zXHai*Qp=h=5+qOlmkw>5G}IXJBg{i}Ak{CkhDGR?5uDW87;#??SBi!y4gHx}8Y6BQ z*%ahT6X3p%^$N{m3j-C*!V6(%*@2=1=Ar z$Y4(J6&Z5|Bx4Sm7HEw4Rc4mPi0=t=CT@ZeLD7G|4+}>BUi7d{hOm>2m z0_)N7aNQu8^uOHbBF}Nk9Pj3UIc@+q*3uX;6sHh_Vdg~g0w)bL zMqGzk2QI>t>fc$ALJh3)k*{A~7(oW_6~)jiF#UD9IuP-Rw1IU|K`2U}kNMcs+*) z8Y6y(nWZt}C6O;!KFq0=%4|;DOPPgE7krc(&mJDZ81YV)>Of<}qm1mRq2_tmR*q+N z!E*Lr1Es-t!SX3i7if&Q7U$ns1eLmVI>!q%M%;qqSzNHJ_wbKF2Kvn7LfQSu*;!vh z`kKQ7jS(MV7CKhcsnx?DML3UnkCO%(Bi_fXZ}>CUsD~FvHby+3Q(GD%o*PE&%_;dH z-Oko30;ZZ{%q)!&{~FmC@m5Y9XpDFbGwain;dCv-+8A-9Z~AyS>p)|~$(&uFG2$DU zDT|jOT4(h+$08deKE-eSsF`mfG(iri?KQKm2<__`gJR8jv<_g)DnYA2Oa=69%6E$yh&}p{+ z1x{GO#1?3bcm=cM00DWMnU&?%c~c@7Bc=mp>Nug7gXZDv{Ev+hzr@2R&=@h<8`88_ zLRMWCkcRV|5zdVc@vI#v8c9YqspC!2IBLWT{{YL}pCg=#|H!oqG)CN;B`wex@otW1 zX^i;I$i|4-1f&*fjCdyNRH4d@(nuC8k08@{I1JnC0WuxM%)&@+%z~)M#)yxyMi^*} z_)})qB0Y&qw6gKKphpCeew?!oG)CN#vkSEEn$FBhq!-`|)RxAGt8-GN%!G>c{LRpc z|Iiq5SFYyY0{ZzDW)}S%HGh6&W5iE!YE`R{>xI$ty;igD6iydtjCchLP@sKR562r6 ze!$h6pAn?%_!}d(v#JnkjJO7Kt4o}Zu-)Zw#>uC^id3*M;$mi&#)!X*Y>YUHuTz8? zBff)kwHDN~9Bw733pWJ`s{bWUv&dj$#49+W)x!N9Rc<}Q=g^u8YbGp5Sgx?8!j=hJEo`l@Q^M#OFV(gfT&q{* zIt-sf>m-bxw^s3P7dA*(uCOt}mI+%f?0~R?!cGV~Ba9vsQgyk}@HsSkj7PCC!X^tV z5w=#?I$@`UofSs+npJ)-!v|Bn!g>iCDlALbjTm8a|kw z5q7h%`-Rb0i7ACcqelW%+Ihlu2-_v>ps>Tj>fj!sN?YIXIkXI61BKl!>|SAXA5x`V zA#9zn3Sno3{U$69_j^=Ym*I10U4(TPHbvM}Ve^DNBJ8NJ`c?IF7(R@1Vd=td7dA-P%fen0_O7t^gnc6HU&4|w zEvs_t7(RzaHx(2cAZ({($4gdG%iLf9E$(YQdW%Al{&kb z1;Qo>dr8UW*tgXw)?w+QPaEJN5#VRX4w)%ks4JB58Aj6Qs);?=`t5LGTI*NQb0 z) z+V-@tw}sKSe^eR22>V^wWl--_TKX)7iq}BcRlkQTPAF|umi#l3ZoAXsdCQh214=gs{hjJt=ITuup}3FYHHQ=Y>T< zccmIQwA&0{oOXvWdb>^4k91uX?-^mw3Hw~wm%>g7`&n2DZd<7QS{gp+w!*pzdq|i^ z*nDA+3VTl23&Oq>_KmQ5IBQbnUSaqgS~FoSgyjkwBW#(l<-*nqTPN(au(QIN!9=hs zw}s(@TnXzgtVCFuu&0DQE9^C4ZwNar?5wb=^~`eP3?Iy#3+p0mvak|ibA>GwwnNx1 zVaJ4>5JoRws`f@3KFsaHZV}c;Scb6a!gOI9g>4bGPuQozlJKghDz}c|b7)P3T`w$K z*xkY=2zx-7E^M~2EyA`7J1;B>CW5I3xbD`HdI)au=|7+30om-m9Pq7n}zKawqKYNudk}Q#2Y?`mMpBX zu$IEw3hO4Ur!bGO>B627_MEWSg}o*0l(3(L#h`Mkeh$Njc}Q3{VGjxO2%9hLQDGkm z`=_w4g?%TiN&~apYKG6DbrjZF*loh@5H?EKXkmXB_77p-3Og$7H(?iqxf+^vNi=*8 zZGf=B!X6ejPuSDK{x0k*Vc!ZnE9^I6agEG!U4{>HqOk751`8V|Y_YH>guN*2Wnmu( z`$$-9W3ybR;e$C~VadW$gtZiQudqB}D}}u(Y?H99!p;kex=PgmbA;i;93kv#VNHc) z3Cj^yBy5r}uds4qTZO$Z>B4kj?+Du@Y>%*yg(X~T)}^N5b7iS6*fcI5@Ab)trE6c*im7}h27ZH ztc%<5!KA*huEM4Wn=0%LVe5r`AnYSyhlG7C?8@uRavK>wTq_lJMi@*JdychyO2g)U z*PDLM6`$_R7^qKj8V!BEaodwHh|-t@!mCpcZ6N-AMP`Jf9M4m!N)N4!H1xUTGsM(x%&oShKw`PJr1 zA9~m`dB0ZZ($jb7&J%j)6VcvYhmR)dRrU8b9CGL#qxB@4-q{xIz5Vb#+Jy;8_h?3& z&|rO=o_@mHYj4qIXt-8XRo~{`ja_e1W&3SK)lj7><*Bx#QSOSq7m5!18mPNGo8z~p zALjP=i`M(ZqcMBYl=LI^jVQFQzRA8FHMVc0UhUVnuqyY<(JHFPdhIGtvt39((4{2( zh!(ABozP+E1J&k&SbgY$?=D9tUntsPbZ7K1>hFq7_Xl^X9MI=gQ8>n_7NhmVe`vF~ zFMBusW9@+Ne*DMk1z$3bFlJTw?t~8-5Pb9COJ?6<_^{H0y$2t3ari!iPvwHTg%|<( z3ZX4I9{ypYw}WxcLhZl@6*cYMpm4p4rr9`D#oG`Rz7OGKCWN*!{OD~m|NQAYaOOuG zPr}y&1+~_?;*{LCQJts`AHglcNweCN5s-qMyT{~=EzHE19JK`8GdhfLo0dDapfGD} zc8*p<>%=c;QwM6=+qP76KqMO=l*O0GqM9}?uOPQDH*YMCK<9*GI9zl;ld45MaRX{X z{ho~bOZ311?NS>{3B$IBS%hjgF=fRASHzI2LqZ`TZA4aKR%Y(l5jo>>@DGj18Zjb2 zr=TEr?A=`PB*cLpiR}R`4VFTxqcKUyiTZ)6SRLPM+K-wwpj~aFtu}HlVn14+Ux;it z_laU;WI6}ZYrdWE)SOLwg!kLq67Ve#y5Xi0=SuwNxFEXO78;+7k_`7q*Ai>Xej2?tU6dpT||92c|v?4tbq%)F5!3vvp%Ce-Qw;M7s* zT2;bQ-oF9g+>6G2sA?D*i#f+#$nj+kYhj}tsnl3)TtQCJh`h}Ftg$0d7vDEWf904} znc)HmZ}D88st`Ee;XcnHS8G)uV&)y(!zjtdaqmG3ll-x@XQPd!5Qf0J{Fvqd3~ zn%Z9O(F7cUgUo+GD-I#&)C9_PGqWpgHzVH+?I{*()eibx>FBJnIb1pJdqi!@m8c0h zRnOW|Lr6w%Vs1AYr^YCK%~R9p(H`~q<6abZkdS7#)uisCg#O)CAV=UVh2VZ39k(4w zHh}lbAvx;y=zXZqbo}UJ>}08@48Nwhwnw)|X~3Hs4FO{-3H)AbBEG6h1BQmM3}Awk zga)MyN%|@)$qw}j^@%A_!xDOM)>ZKKuZG_1lfXAX=|-Ws(Oi;(9q3s`4{6$5O)I7e zVliCkf_Q~RE4~5llW=c=`xM;HaF@ZQWu}$KyACdX#c#vKuXr=u4R8;_g})eiYTMzSf%^em61AOh?QnO&tqpfC z+{SSC!6hl!54VM}-`3ctBmOyfD%>yNX2Sgn?n7|Dh5HEH@8B+i`#szz;BJJw(%7f@ z{y6q&&Y^bFvA6<1bz_%&>c%el9NJMMG>+16JO?C8`Qo&yh7UJ}gmn2|P1p`$Cx!ha3}e#BuZrQrw+e;PcW71HnhR?sY>=>_!peksg^?8; zRcHD(t;+8$Vebh0SlDO6$lQlYTgC9j-lGua5`s}Gcz`HOWKKIXyx0Y$}P!+b8 z#fqv8ux2!RI-i1x@zukRK*R(lEGSGEpF(uW{d%k_BD9clJJwk1$^yv#11}3ae z!Jg7`fnbDkpzI*LuWB1PXt0DJ8X+TsgmBZF=%v3?KHlil@M)Fsbv_;4r9G-MbrR;; zOjc0+w9{&+8_l3eSPo1*m1fR*%-rJpL435-s!;0UWb7qr&BS*Xd<~i5P=@HFqYz3* z)m%DACna5$;*#4nD0~zJaHytDh3{k9^Gp94hb!IeJ%r5;3a`aFt19gz!lt6Uwn2vJ zs7_S&Ah^@9HmR-T?wqkX`B{ZIrYe_HV5OB(n!j?YhPKzW&b%a(g3Wbfu2e>{6=+ijOl^w}_ijZ2_NyWsaV{DymW)@~Qn^~aekiBVo zu5iq_O#Tu&E5;;G;WWpYoaauBjPlV}(qXSCCqK_WAtaC#G!>XTc3hG9$#v4VX>it( zP(v;DPYq!;6^~40@Bbs^gMOrV&`~!xU$eCTiQ+;1E{aEOC?1q0=}7^7$=``bUr=*= zJwzXsr$I>6ul=lrZSrxmw>I|*)Ixc9@o1MUNGv*11mcQo9|a7q220vA8+A-FT(mcZQw7vrdy#*qi^ z=Wt8m(%8T`UGaIi)8N*ju>hBJ4+uapjg4}+)bkDSQ#u3rl+HjthemURVw9g^Rct1s zSy(Z87>s;zY^G4L&ceDGK8IEyY=W@q!gOIRW7wkH4kL_b-bkGrO(Z^^jUB z7F#q>ZB;OQ!+udvHhvpNFrzc{%rRM` zN9SepzNQhOjrvY)CPDLqNJA4ysvAOxn#8FUWdI8m*w2^OAr#wDb1>l9`!3>fVCFdlfWO`Og_q+9m|zj49WcZ!^bdjV{X3 zGPCo>O)_TK%!zsVrk78xP?vF|vb4;RxuZvC`d@KTL@ft?exFg+%rFaL$4umbll# z+W8pynx~|+rijhkxQ&pz96g~>e|+@uL2V#`=4$CbeyQ(h^v)uW|K^A{$0v_r4#Ggf zkPFy4YVoQ585!|(Ci8<;!R-C{`poY6U11vx{;H*eW|2re2G=4KDc%D+2rY>OM{Sl_@$ z_J*wS6I(Pxa_B2~9w(V5n?wli8(B2;l-r96EXW&KnB1iQwaIn`xbf^AZ`}A&+ncA~YT93?(TL-7(Ql$zj){L-z1N-#voRN8J zZxsuwN-QTZW zp9(a}b7J=fm4EA&oI3?l?ws2h>@3F*U8Kd^ZkTt|`Y(H|JyrXBwP(-n_hKcdH6h;C zvD0;wOXFmPrmk!J8u0FoA z;gc92F_#CzYZCfpLchD)|h0-Oin>^ zlZkCxUpr(1W{$iG1iJG-0@JwhZGd#w8(@+xLaKEtf3l=$s4P({m(i< zEm77v@rdRDHa@qYC~I_bL1EE|+`J(zQku6x4~`jAgc*I(kn!2lbMQ8AiJorOq7}t4 zJ7?mUF%UU)v~^h*f9U*=*nif3QwYZ7jLF7ARDjy4xeg+TWwU332TC!`f8({9H3t;_ zw5UtmurBYU-!bUOb4Nyu0Keq(pv;`j#*G-Ro&4{qfvmNl1-{LH`LF|rQv<0lunx9v z-pX&u`{Q-6MT-=UPwQZPUI%xz$E0AC9c~>gq>}u%FzaAvC}YnA#p`IX4u0$M&rH)e zo}VsCp>#mAF<1I;$?<*f^4DuAY#b&ndh@#tgo8HH7CXjc{SC_RVeq*|9EwLRhbw-ot}LY!DSg~fIye&Omz%Wj9Z zcpDf$+Gx;(Ywz_aXcyv~Gn94`Mb0mu?!{3`wbA*`bETZBHrdO@%~MH_jzP@?|)g}%^8~wJsIl9 zf2!!BuB4-HYu9dOE4TkreT97%}6sGDqhY6yknqY{CxI-e^u*-dLL5(WqE% zr*SS&IB6W+?pMr+%B&6;b-2OO^Yioa)AB~(%4|GBbkfLiaUg57c}|dws*zS6PNk1S ziYJhw%dI`rrCvq_a3aF>3R3&&G=f?yiav!?9+|m$!;41ZGG%PSBHGO)9oVSJxI9!K zC%*vcF7CYG%5(qRe#4I4k0p(HVSj@UW8NXd2&A{)Ff8|plW*^Ta>tIHm+jm~~{ z#=LRbXLS#}TlQ7#&zG${{+FITHLVwxzIdB`=)w_|oNstlgY-+vNXx)+nnbm({$*B`XXabE)brSxKLuy8jEAOSiPR z6vsdv%}Y`7z?`I(m!gtNnlF7$a^xU$=A%mR-_4&1)vO&uMwhBpdPm+t*C+I7Y?*y(m`y+;h5vzQuFmmb0Io-M`^z z?1m$;<-Iqa-Lv7l*t5IJ2kh{C_1lK;W8?OhcRAN+o9C+=2bNFyM&EdL*M{S5f z9<5|JE=&%ega-zopwNYATu)ceLE1FmbDMNLHEjUYTkEga(d}-IX8fa5Fk>sOfx4+@ z>qrxwi1UCx38&yoF=N1``qjaYn$j3Q+R`xRmep_^F$@-1x z8=-Oh2##Wv!p<2!+*F13sM69cToun>TCO8$xzS%*o+Lqe=jqsvINMJtEpiu#B4={LjRW;n@}`EWGFD-8-KxiW7;k=*RS zFIaA}e2hAxBHV2{OoIAjb*uEP6tNlD2OohDh!ktu&9 zCzKBrNm4@(p$E&D%8vv6WQ=N&Eiz_Yk>NWfnC7W$_fR9xk(82O7cX91cY?b-X`X$zzWwY+?Ke!gx{H06iZ^+G z`?H0$i*HH6dk=kV?N1iP>Ajr#mds(^grS=<-4(-pQ`ZPo%iQS7B5h{Z($qy)qo~X1 zHxNJC%m>`>#c$%{5T~t_DIA!p=m9HrY0(r%D5B12Yn(oA_rGQax&rM;_d{d zkPZoTF~!(4DE$y2dL-OBFk}g zW3HseQd4Q}r1Giy<5{k;a|*vX_?a8^Ayt%$DK+4BO)IAE-wBs8*bSG$_rRqqvisoH zhx;+y#&AD{doA40;5LVg=WL2^f_o5dPq<&f?F08PTnrcOYq)p7Jp`AI9qm&&G_9*4 zLq0WR$ft&kV%v;(4()*9i=%Qltun@>;>AKw%pA6s zo∓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�-*i2MFK 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ⅇY!POx_s`_Q_g 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 diff --git a/src/Native/libubqhash/libubqhash.vcxproj b/src/Native/libubqhash/libubqhash.vcxproj index c6189d8e6..b8d6360b1 100644 --- a/src/Native/libubqhash/libubqhash.vcxproj +++ b/src/Native/libubqhash/libubqhash.vcxproj @@ -73,22 +73,22 @@ true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) @@ -105,7 +105,7 @@ Windows true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) @@ -122,7 +122,7 @@ Windows true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) @@ -143,7 +143,7 @@ true true true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) @@ -164,7 +164,7 @@ true true true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium.h b/src/Native/libubqhash/windows/include/libsodium/sodium.h deleted file mode 100644 index 1f79e87bf..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium.h +++ /dev/null @@ -1,68 +0,0 @@ - -#ifndef sodium_H -#define sodium_H - -#include "sodium/version.h" - -#include "sodium/core.h" -#include "sodium/crypto_aead_aes256gcm.h" -#include "sodium/crypto_aead_chacha20poly1305.h" -#include "sodium/crypto_aead_xchacha20poly1305.h" -#include "sodium/crypto_auth.h" -#include "sodium/crypto_auth_hmacsha256.h" -#include "sodium/crypto_auth_hmacsha512.h" -#include "sodium/crypto_auth_hmacsha512256.h" -#include "sodium/crypto_box.h" -#include "sodium/crypto_box_curve25519xsalsa20poly1305.h" -#include "sodium/crypto_core_hsalsa20.h" -#include "sodium/crypto_core_hchacha20.h" -#include "sodium/crypto_core_salsa20.h" -#include "sodium/crypto_core_salsa2012.h" -#include "sodium/crypto_core_salsa208.h" -#include "sodium/crypto_generichash.h" -#include "sodium/crypto_generichash_blake2b.h" -#include "sodium/crypto_hash.h" -#include "sodium/crypto_hash_sha256.h" -#include "sodium/crypto_hash_sha512.h" -#include "sodium/crypto_kdf.h" -#include "sodium/crypto_kdf_blake2b.h" -#include "sodium/crypto_kx.h" -#include "sodium/crypto_onetimeauth.h" -#include "sodium/crypto_onetimeauth_poly1305.h" -#include "sodium/crypto_pwhash.h" -#include "sodium/crypto_pwhash_argon2i.h" -#include "sodium/crypto_scalarmult.h" -#include "sodium/crypto_scalarmult_curve25519.h" -#include "sodium/crypto_secretbox.h" -#include "sodium/crypto_secretbox_xsalsa20poly1305.h" -#include "sodium/crypto_shorthash.h" -#include "sodium/crypto_shorthash_siphash24.h" -#include "sodium/crypto_sign.h" -#include "sodium/crypto_sign_ed25519.h" -#include "sodium/crypto_stream.h" -#include "sodium/crypto_stream_chacha20.h" -#include "sodium/crypto_stream_salsa20.h" -#include "sodium/crypto_stream_xsalsa20.h" -#include "sodium/crypto_verify_16.h" -#include "sodium/crypto_verify_32.h" -#include "sodium/crypto_verify_64.h" -#include "sodium/randombytes.h" -#ifdef __native_client__ -# include "sodium/randombytes_nativeclient.h" -#endif -#include "sodium/randombytes_salsa20_random.h" -#include "sodium/randombytes_sysrandom.h" -#include "sodium/runtime.h" -#include "sodium/utils.h" - -#ifndef SODIUM_LIBRARY_MINIMAL -# include "sodium/crypto_box_curve25519xchacha20poly1305.h" -# include "sodium/crypto_secretbox_xchacha20poly1305.h" -# include "sodium/crypto_pwhash_scryptsalsa208sha256.h" -# include "sodium/crypto_stream_aes128ctr.h" -# include "sodium/crypto_stream_salsa2012.h" -# include "sodium/crypto_stream_salsa208.h" -# include "sodium/crypto_stream_xchacha20.h" -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/core.h b/src/Native/libubqhash/windows/include/libsodium/sodium/core.h deleted file mode 100644 index 3ca447628..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/core.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef sodium_core_H -#define sodium_core_H - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -int sodium_init(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h deleted file mode 100644 index 972df54f6..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h +++ /dev/null @@ -1,145 +0,0 @@ -#ifndef crypto_aead_aes256gcm_H -#define crypto_aead_aes256gcm_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -SODIUM_EXPORT -int crypto_aead_aes256gcm_is_available(void); - -#define crypto_aead_aes256gcm_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_keybytes(void); - -#define crypto_aead_aes256gcm_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_nsecbytes(void); - -#define crypto_aead_aes256gcm_NPUBBYTES 12U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_npubbytes(void); - -#define crypto_aead_aes256gcm_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_abytes(void); - -typedef CRYPTO_ALIGN(16) unsigned char crypto_aead_aes256gcm_state[512]; - -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_statebytes(void); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* -- Precomputation interface -- */ - -SODIUM_EXPORT -int crypto_aead_aes256gcm_beforenm(crypto_aead_aes256gcm_state *ctx_, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_afternm(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_afternm(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_detached_afternm(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_detached_afternm(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_aes256gcm_keygen(unsigned char k[crypto_aead_aes256gcm_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h deleted file mode 100644 index 0bbc68859..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef crypto_aead_chacha20poly1305_H -#define crypto_aead_chacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -/* -- IETF ChaCha20-Poly1305 construction with a 96-bit nonce and a 32-bit internal counter -- */ - -#define crypto_aead_chacha20poly1305_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_keybytes(void); - -#define crypto_aead_chacha20poly1305_ietf_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_nsecbytes(void); - -#define crypto_aead_chacha20poly1305_ietf_NPUBBYTES 12U - -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_npubbytes(void); - -#define crypto_aead_chacha20poly1305_ietf_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_abytes(void); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_chacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_chacha20poly1305_ietf_KEYBYTES]); - -/* -- Original ChaCha20-Poly1305 construction with a 64-bit nonce and a 64-bit internal counter -- */ - -#define crypto_aead_chacha20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_keybytes(void); - -#define crypto_aead_chacha20poly1305_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_nsecbytes(void); - -#define crypto_aead_chacha20poly1305_NPUBBYTES 8U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_npubbytes(void); - -#define crypto_aead_chacha20poly1305_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_abytes(void); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_chacha20poly1305_keygen(unsigned char k[crypto_aead_chacha20poly1305_KEYBYTES]); - -/* Aliases */ - -#define crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_ietf_KEYBYTES -#define crypto_aead_chacha20poly1305_IETF_NSECBYTES crypto_aead_chacha20poly1305_ietf_NSECBYTES -#define crypto_aead_chacha20poly1305_IETF_NPUBBYTES crypto_aead_chacha20poly1305_ietf_NPUBBYTES -#define crypto_aead_chacha20poly1305_IETF_ABYTES crypto_aead_chacha20poly1305_ietf_ABYTES - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h deleted file mode 100644 index f863ce88c..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef crypto_aead_xchacha20poly1305_H -#define crypto_aead_xchacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_aead_xchacha20poly1305_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_keybytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_nsecbytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_NPUBBYTES 24U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_npubbytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_abytes(void); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_aead_xchacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES]); - -/* Aliases */ - -#define crypto_aead_xchacha20poly1305_IETF_KEYBYTES crypto_aead_xchacha20poly1305_ietf_KEYBYTES -#define crypto_aead_xchacha20poly1305_IETF_NSECBYTES crypto_aead_xchacha20poly1305_ietf_NSECBYTES -#define crypto_aead_xchacha20poly1305_IETF_NPUBBYTES crypto_aead_xchacha20poly1305_ietf_NPUBBYTES -#define crypto_aead_xchacha20poly1305_IETF_ABYTES crypto_aead_xchacha20poly1305_ietf_ABYTES - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth.h deleted file mode 100644 index 7174e7bce..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef crypto_auth_H -#define crypto_auth_H - -#include - -#include "crypto_auth_hmacsha512256.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES -SODIUM_EXPORT -size_t crypto_auth_bytes(void); - -#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES -SODIUM_EXPORT -size_t crypto_auth_keybytes(void); - -#define crypto_auth_PRIMITIVE "hmacsha512256" -SODIUM_EXPORT -const char *crypto_auth_primitive(void); - -SODIUM_EXPORT -int crypto_auth(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_verify(const unsigned char *h, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_auth_keygen(unsigned char k[crypto_auth_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h deleted file mode 100644 index deec5266e..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef crypto_auth_hmacsha256_H -#define crypto_auth_hmacsha256_H - -#include -#include "crypto_hash_sha256.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha256_BYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_bytes(void); - -#define crypto_auth_hmacsha256_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha256(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* ------------------------------------------------------------------------- */ - -typedef struct crypto_auth_hmacsha256_state { - crypto_hash_sha256_state ictx; - crypto_hash_sha256_state octx; -} crypto_auth_hmacsha256_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_init(crypto_auth_hmacsha256_state *state, - const unsigned char *key, - size_t keylen); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_update(crypto_auth_hmacsha256_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_final(crypto_auth_hmacsha256_state *state, - unsigned char *out); - - -SODIUM_EXPORT -void crypto_auth_hmacsha256_keygen(unsigned char k[crypto_auth_hmacsha256_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h deleted file mode 100644 index 77a55fbc0..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef crypto_auth_hmacsha512_H -#define crypto_auth_hmacsha512_H - -#include -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha512_BYTES 64U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_bytes(void); - -#define crypto_auth_hmacsha512_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* ------------------------------------------------------------------------- */ - -typedef struct crypto_auth_hmacsha512_state { - crypto_hash_sha512_state ictx; - crypto_hash_sha512_state octx; -} crypto_auth_hmacsha512_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_init(crypto_auth_hmacsha512_state *state, - const unsigned char *key, - size_t keylen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_update(crypto_auth_hmacsha512_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_final(crypto_auth_hmacsha512_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_auth_hmacsha512_keygen(unsigned char k[crypto_auth_hmacsha512_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h deleted file mode 100644 index 4842f3deb..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef crypto_auth_hmacsha512256_H -#define crypto_auth_hmacsha512256_H - -#include -#include "crypto_auth_hmacsha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha512256_BYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_bytes(void); - -#define crypto_auth_hmacsha512256_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256(unsigned char *out, const unsigned char *in, - unsigned long long inlen,const unsigned char *k); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* ------------------------------------------------------------------------- */ - -typedef crypto_auth_hmacsha512_state crypto_auth_hmacsha512256_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_init(crypto_auth_hmacsha512256_state *state, - const unsigned char *key, - size_t keylen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_update(crypto_auth_hmacsha512256_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_final(crypto_auth_hmacsha512256_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_auth_hmacsha512256_keygen(unsigned char k[crypto_auth_hmacsha512256_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box.h deleted file mode 100644 index 614cd1e0a..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef crypto_box_H -#define crypto_box_H - -/* - * THREAD SAFETY: crypto_box_keypair() is thread-safe, - * provided that sodium_init() was called before. - * - * Other functions are always thread-safe. - */ - -#include - -#include "crypto_box_curve25519xsalsa20poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_SEEDBYTES crypto_box_curve25519xsalsa20poly1305_SEEDBYTES -SODIUM_EXPORT -size_t crypto_box_seedbytes(void); - -#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES -SODIUM_EXPORT -size_t crypto_box_publickeybytes(void); - -#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES -SODIUM_EXPORT -size_t crypto_box_secretkeybytes(void); - -#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES -SODIUM_EXPORT -size_t crypto_box_noncebytes(void); - -#define crypto_box_MACBYTES crypto_box_curve25519xsalsa20poly1305_MACBYTES -SODIUM_EXPORT -size_t crypto_box_macbytes(void); - -#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" -SODIUM_EXPORT -const char *crypto_box_primitive(void); - -SODIUM_EXPORT -int crypto_box_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_box_keypair(unsigned char *pk, unsigned char *sk); - -SODIUM_EXPORT -int crypto_box_easy(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_open_easy(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_detached(unsigned char *c, unsigned char *mac, - const unsigned char *m, unsigned long long mlen, - const unsigned char *n, const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_open_detached(unsigned char *m, const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -/* -- Precomputation interface -- */ - -#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES -SODIUM_EXPORT -size_t crypto_box_beforenmbytes(void); - -SODIUM_EXPORT -int crypto_box_beforenm(unsigned char *k, const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_easy_afternm(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_open_easy_afternm(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_detached_afternm(unsigned char *c, unsigned char *mac, - const unsigned char *m, unsigned long long mlen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_open_detached_afternm(unsigned char *m, const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* -- Ephemeral SK interface -- */ - -#define crypto_box_SEALBYTES (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_sealbytes(void); - -SODIUM_EXPORT -int crypto_box_seal(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *pk); - -SODIUM_EXPORT -int crypto_box_seal_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES -SODIUM_EXPORT -size_t crypto_box_zerobytes(void); - -#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES -SODIUM_EXPORT -size_t crypto_box_boxzerobytes(void); - -SODIUM_EXPORT -int crypto_box(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_afternm(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_open_afternm(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h deleted file mode 100644 index b781cc6e8..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h +++ /dev/null @@ -1,153 +0,0 @@ - -#ifndef crypto_box_curve25519xchacha20poly1305_H -#define crypto_box_curve25519xchacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_curve25519xchacha20poly1305_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_seedbytes(void); - -#define crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_publickeybytes(void); - -#define crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_secretkeybytes(void); - -#define crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_beforenmbytes(void); - -#define crypto_box_curve25519xchacha20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_noncebytes(void); - -#define crypto_box_curve25519xchacha20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_macbytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seed_keypair(unsigned char *pk, - unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_keypair(unsigned char *pk, - unsigned char *sk); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_easy(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_easy(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_detached(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -/* -- Precomputation interface -- */ - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_beforenm(unsigned char *k, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_easy_afternm(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_easy_afternm(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_detached_afternm(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_detached_afternm(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -/* -- Ephemeral SK interface -- */ - -#define crypto_box_curve25519xchacha20poly1305_SEALBYTES \ - (crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES + \ - crypto_box_curve25519xchacha20poly1305_MACBYTES) - -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_sealbytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seal(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seal_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h deleted file mode 100644 index 9b5a39c3f..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef crypto_box_curve25519xsalsa20poly1305_H -#define crypto_box_curve25519xsalsa20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_curve25519xsalsa20poly1305_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_seedbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_publickeybytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_secretkeybytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_beforenmbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_noncebytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_macbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_boxzerobytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES \ - (crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES + \ - crypto_box_curve25519xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_zerobytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_seed_keypair(unsigned char *pk, - unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_keypair(unsigned char *pk, - unsigned char *sk); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_beforenm(unsigned char *k, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_afternm(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_open_afternm(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hchacha20.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hchacha20.h deleted file mode 100644 index 05e5670c1..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hchacha20.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_hchacha20_H -#define crypto_core_hchacha20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_hchacha20_OUTPUTBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hchacha20_outputbytes(void); - -#define crypto_core_hchacha20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hchacha20_inputbytes(void); - -#define crypto_core_hchacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hchacha20_keybytes(void); - -#define crypto_core_hchacha20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hchacha20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_hchacha20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h deleted file mode 100644 index 82e475b8f..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_hsalsa20_H -#define crypto_core_hsalsa20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_hsalsa20_OUTPUTBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_outputbytes(void); - -#define crypto_core_hsalsa20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_inputbytes(void); - -#define crypto_core_hsalsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_keybytes(void); - -#define crypto_core_hsalsa20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_hsalsa20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa20.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa20.h deleted file mode 100644 index 160cc56d2..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa20.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_salsa20_H -#define crypto_core_salsa20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa20_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa20_outputbytes(void); - -#define crypto_core_salsa20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa20_inputbytes(void); - -#define crypto_core_salsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa20_keybytes(void); - -#define crypto_core_salsa20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa2012.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa2012.h deleted file mode 100644 index bdd5f9fdb..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa2012.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_salsa2012_H -#define crypto_core_salsa2012_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa2012_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa2012_outputbytes(void); - -#define crypto_core_salsa2012_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa2012_inputbytes(void); - -#define crypto_core_salsa2012_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa2012_keybytes(void); - -#define crypto_core_salsa2012_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa2012_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa2012(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa208.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa208.h deleted file mode 100644 index 3c13efa4e..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_core_salsa208.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef crypto_core_salsa208_H -#define crypto_core_salsa208_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa208_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa208_outputbytes(void); - -#define crypto_core_salsa208_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa208_inputbytes(void); - -#define crypto_core_salsa208_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa208_keybytes(void); - -#define crypto_core_salsa208_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa208_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa208(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash.h deleted file mode 100644 index 2398fb9db..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef crypto_generichash_H -#define crypto_generichash_H - -#include - -#include "crypto_generichash_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_generichash_BYTES_MIN crypto_generichash_blake2b_BYTES_MIN -SODIUM_EXPORT -size_t crypto_generichash_bytes_min(void); - -#define crypto_generichash_BYTES_MAX crypto_generichash_blake2b_BYTES_MAX -SODIUM_EXPORT -size_t crypto_generichash_bytes_max(void); - -#define crypto_generichash_BYTES crypto_generichash_blake2b_BYTES -SODIUM_EXPORT -size_t crypto_generichash_bytes(void); - -#define crypto_generichash_KEYBYTES_MIN crypto_generichash_blake2b_KEYBYTES_MIN -SODIUM_EXPORT -size_t crypto_generichash_keybytes_min(void); - -#define crypto_generichash_KEYBYTES_MAX crypto_generichash_blake2b_KEYBYTES_MAX -SODIUM_EXPORT -size_t crypto_generichash_keybytes_max(void); - -#define crypto_generichash_KEYBYTES crypto_generichash_blake2b_KEYBYTES -SODIUM_EXPORT -size_t crypto_generichash_keybytes(void); - -#define crypto_generichash_PRIMITIVE "blake2b" -SODIUM_EXPORT -const char *crypto_generichash_primitive(void); - -typedef crypto_generichash_blake2b_state crypto_generichash_state; - -SODIUM_EXPORT -size_t crypto_generichash_statebytes(void); - -SODIUM_EXPORT -int crypto_generichash(unsigned char *out, size_t outlen, - const unsigned char *in, unsigned long long inlen, - const unsigned char *key, size_t keylen); - -SODIUM_EXPORT -int crypto_generichash_init(crypto_generichash_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen); - -SODIUM_EXPORT -int crypto_generichash_update(crypto_generichash_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_generichash_final(crypto_generichash_state *state, - unsigned char *out, const size_t outlen); - -SODIUM_EXPORT -void crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h deleted file mode 100644 index 9326a04ad..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef crypto_generichash_blake2b_H -#define crypto_generichash_blake2b_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack(1) -#else -# pragma pack(push, 1) -#endif - -typedef struct CRYPTO_ALIGN(64) crypto_generichash_blake2b_state { - uint64_t h[8]; - uint64_t t[2]; - uint64_t f[2]; - uint8_t buf[2 * 128]; - size_t buflen; - uint8_t last_node; -} crypto_generichash_blake2b_state; - -#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack() -#else -# pragma pack(pop) -#endif - -#define crypto_generichash_blake2b_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes_min(void); - -#define crypto_generichash_blake2b_BYTES_MAX 64U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes_max(void); - -#define crypto_generichash_blake2b_BYTES 32U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes(void); - -#define crypto_generichash_blake2b_KEYBYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes_min(void); - -#define crypto_generichash_blake2b_KEYBYTES_MAX 64U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes_max(void); - -#define crypto_generichash_blake2b_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes(void); - -#define crypto_generichash_blake2b_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_saltbytes(void); - -#define crypto_generichash_blake2b_PERSONALBYTES 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_personalbytes(void); - -SODIUM_EXPORT -size_t crypto_generichash_blake2b_statebytes(void); - -SODIUM_EXPORT -int crypto_generichash_blake2b(unsigned char *out, size_t outlen, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *key, size_t keylen); - -SODIUM_EXPORT -int crypto_generichash_blake2b_salt_personal(unsigned char *out, size_t outlen, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *key, - size_t keylen, - const unsigned char *salt, - const unsigned char *personal); - -SODIUM_EXPORT -int crypto_generichash_blake2b_init(crypto_generichash_blake2b_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen); - -SODIUM_EXPORT -int crypto_generichash_blake2b_init_salt_personal(crypto_generichash_blake2b_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen, - const unsigned char *salt, - const unsigned char *personal); - -SODIUM_EXPORT -int crypto_generichash_blake2b_update(crypto_generichash_blake2b_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_generichash_blake2b_final(crypto_generichash_blake2b_state *state, - unsigned char *out, - const size_t outlen); - -SODIUM_EXPORT -void crypto_generichash_blake2b_keygen(unsigned char k[crypto_generichash_blake2b_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash.h deleted file mode 100644 index 302ed5c5e..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef crypto_hash_H -#define crypto_hash_H - -/* - * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA512, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include - -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_hash_BYTES crypto_hash_sha512_BYTES -SODIUM_EXPORT -size_t crypto_hash_bytes(void); - -SODIUM_EXPORT -int crypto_hash(unsigned char *out, const unsigned char *in, - unsigned long long inlen); - -#define crypto_hash_PRIMITIVE "sha512" -SODIUM_EXPORT -const char *crypto_hash_primitive(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha256.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha256.h deleted file mode 100644 index f64d16e0e..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha256.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef crypto_hash_sha256_H -#define crypto_hash_sha256_H - -/* - * WARNING: Unless you absolutely need to use SHA256 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA256, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_hash_sha256_state { - uint32_t state[8]; - uint64_t count; - uint8_t buf[64]; -} crypto_hash_sha256_state; - -SODIUM_EXPORT -size_t crypto_hash_sha256_statebytes(void); - -#define crypto_hash_sha256_BYTES 32U -SODIUM_EXPORT -size_t crypto_hash_sha256_bytes(void); - -SODIUM_EXPORT -int crypto_hash_sha256(unsigned char *out, const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha256_init(crypto_hash_sha256_state *state); - -SODIUM_EXPORT -int crypto_hash_sha256_update(crypto_hash_sha256_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha256_final(crypto_hash_sha256_state *state, - unsigned char *out); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha512.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha512.h deleted file mode 100644 index 6b0330f14..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_hash_sha512.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef crypto_hash_sha512_H -#define crypto_hash_sha512_H - -/* - * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA512, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_hash_sha512_state { - uint64_t state[8]; - uint64_t count[2]; - uint8_t buf[128]; -} crypto_hash_sha512_state; - -SODIUM_EXPORT -size_t crypto_hash_sha512_statebytes(void); - -#define crypto_hash_sha512_BYTES 64U -SODIUM_EXPORT -size_t crypto_hash_sha512_bytes(void); - -SODIUM_EXPORT -int crypto_hash_sha512(unsigned char *out, const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha512_init(crypto_hash_sha512_state *state); - -SODIUM_EXPORT -int crypto_hash_sha512_update(crypto_hash_sha512_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_hash_sha512_final(crypto_hash_sha512_state *state, - unsigned char *out); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf.h deleted file mode 100644 index 52e496a74..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef crypto_kdf_H -#define crypto_kdf_H - -#include -#include - -#include "crypto_kdf_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kdf_BYTES_MIN crypto_kdf_blake2b_BYTES_MIN -SODIUM_EXPORT -size_t crypto_kdf_bytes_min(void); - -#define crypto_kdf_BYTES_MAX crypto_kdf_blake2b_BYTES_MAX -SODIUM_EXPORT -size_t crypto_kdf_bytes_max(void); - -#define crypto_kdf_CONTEXTBYTES crypto_kdf_blake2b_CONTEXTBYTES -SODIUM_EXPORT -size_t crypto_kdf_contextbytes(void); - -#define crypto_kdf_KEYBYTES crypto_kdf_blake2b_KEYBYTES -SODIUM_EXPORT -size_t crypto_kdf_keybytes(void); - -#define crypto_kdf_PRIMITIVE "blake2b" -SODIUM_EXPORT -const char *crypto_kdf_primitive(void) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len, - uint64_t subkey_id, - const char ctx[crypto_kdf_CONTEXTBYTES], - const unsigned char key[crypto_kdf_KEYBYTES]); - -SODIUM_EXPORT -void crypto_kdf_keygen(unsigned char k[crypto_kdf_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h deleted file mode 100644 index 5480ebe82..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef crypto_kdf_blake2b_H -#define crypto_kdf_blake2b_H - -#include -#include - -#include "crypto_kdf_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kdf_blake2b_BYTES_MIN 16 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_bytes_min(void); - -#define crypto_kdf_blake2b_BYTES_MAX 64 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_bytes_max(void); - -#define crypto_kdf_blake2b_CONTEXTBYTES 8 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_contextbytes(void); - -#define crypto_kdf_blake2b_KEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_keybytes(void); - -SODIUM_EXPORT -int crypto_kdf_blake2b_derive_from_key(unsigned char *subkey, size_t subkey_len, - uint64_t subkey_id, - const char ctx[crypto_kdf_blake2b_CONTEXTBYTES], - const unsigned char key[crypto_kdf_blake2b_KEYBYTES]); -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kx.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kx.h deleted file mode 100644 index d1fce90da..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_kx.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef crypto_kx_H -#define crypto_kx_H - -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kx_PUBLICKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_publickeybytes(void); - -#define crypto_kx_SECRETKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_secretkeybytes(void); - -#define crypto_kx_SEEDBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_seedbytes(void); - -#define crypto_kx_SESSIONKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_sessionkeybytes(void); - -#define crypto_kx_PRIMITIVE "x25519blake2b" -SODIUM_EXPORT -const char *crypto_kx_primitive(void); - -SODIUM_EXPORT -int crypto_kx_seed_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], - unsigned char sk[crypto_kx_SECRETKEYBYTES], - const unsigned char seed[crypto_kx_SEEDBYTES]); - -SODIUM_EXPORT -int crypto_kx_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], - unsigned char sk[crypto_kx_SECRETKEYBYTES]); - -SODIUM_EXPORT -int crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], - unsigned char tx[crypto_kx_SESSIONKEYBYTES], - const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES], - const unsigned char client_sk[crypto_kx_SECRETKEYBYTES], - const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES]) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_kx_server_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], - unsigned char tx[crypto_kx_SESSIONKEYBYTES], - const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES], - const unsigned char server_sk[crypto_kx_SECRETKEYBYTES], - const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES]) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth.h deleted file mode 100644 index 5951c5b82..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef crypto_onetimeauth_H -#define crypto_onetimeauth_H - -#include - -#include "crypto_onetimeauth_poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef crypto_onetimeauth_poly1305_state crypto_onetimeauth_state; - -SODIUM_EXPORT -size_t crypto_onetimeauth_statebytes(void); - -#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES -SODIUM_EXPORT -size_t crypto_onetimeauth_bytes(void); - -#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES -SODIUM_EXPORT -size_t crypto_onetimeauth_keybytes(void); - -#define crypto_onetimeauth_PRIMITIVE "poly1305" -SODIUM_EXPORT -const char *crypto_onetimeauth_primitive(void); - -SODIUM_EXPORT -int crypto_onetimeauth(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -SODIUM_EXPORT -int crypto_onetimeauth_verify(const unsigned char *h, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_onetimeauth_init(crypto_onetimeauth_state *state, - const unsigned char *key); - -SODIUM_EXPORT -int crypto_onetimeauth_update(crypto_onetimeauth_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_onetimeauth_final(crypto_onetimeauth_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_onetimeauth_keygen(unsigned char k[crypto_onetimeauth_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h deleted file mode 100644 index 4b89c4f01..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef crypto_onetimeauth_poly1305_H -#define crypto_onetimeauth_poly1305_H - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#include -#include -#include - -#include - -#include "export.h" - -typedef struct CRYPTO_ALIGN(16) crypto_onetimeauth_poly1305_state { - unsigned char opaque[256]; -} crypto_onetimeauth_poly1305_state; - -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_statebytes(void); - -#define crypto_onetimeauth_poly1305_BYTES 16U -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_bytes(void); - -#define crypto_onetimeauth_poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_keybytes(void); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_init(crypto_onetimeauth_poly1305_state *state, - const unsigned char *key); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_update(crypto_onetimeauth_poly1305_state *state, - const unsigned char *in, - unsigned long long inlen); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_final(crypto_onetimeauth_poly1305_state *state, - unsigned char *out); - -SODIUM_EXPORT -void crypto_onetimeauth_poly1305_keygen(unsigned char k[crypto_onetimeauth_poly1305_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash.h deleted file mode 100644 index 7ecd8b071..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef crypto_pwhash_H -#define crypto_pwhash_H - -#include - -#include "crypto_pwhash_argon2i.h" -#include "crypto_pwhash_argon2id.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_ALG_ARGON2I13 crypto_pwhash_argon2i_ALG_ARGON2I13 -SODIUM_EXPORT -int crypto_pwhash_alg_argon2i13(void); - -#define crypto_pwhash_ALG_ARGON2ID13 crypto_pwhash_argon2id_ALG_ARGON2ID13 -SODIUM_EXPORT -int crypto_pwhash_alg_argon2id13(void); - -#define crypto_pwhash_ALG_DEFAULT crypto_pwhash_ALG_ARGON2I13 -SODIUM_EXPORT -int crypto_pwhash_alg_default(void); - -#define crypto_pwhash_BYTES_MIN crypto_pwhash_argon2i_BYTES_MIN -SODIUM_EXPORT -size_t crypto_pwhash_bytes_min(void); - -#define crypto_pwhash_BYTES_MAX crypto_pwhash_argon2i_BYTES_MAX -SODIUM_EXPORT -size_t crypto_pwhash_bytes_max(void); - -#define crypto_pwhash_PASSWD_MIN crypto_pwhash_argon2i_PASSWD_MIN -SODIUM_EXPORT -size_t crypto_pwhash_passwd_min(void); - -#define crypto_pwhash_PASSWD_MAX crypto_pwhash_argon2i_PASSWD_MAX -SODIUM_EXPORT -size_t crypto_pwhash_passwd_max(void); - -#define crypto_pwhash_SALTBYTES crypto_pwhash_argon2i_SALTBYTES -SODIUM_EXPORT -size_t crypto_pwhash_saltbytes(void); - -#define crypto_pwhash_STRBYTES crypto_pwhash_argon2i_STRBYTES -SODIUM_EXPORT -size_t crypto_pwhash_strbytes(void); - -#define crypto_pwhash_STRPREFIX crypto_pwhash_argon2i_STRPREFIX -SODIUM_EXPORT -const char *crypto_pwhash_strprefix(void); - -#define crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_argon2i_OPSLIMIT_MIN -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_min(void); - -#define crypto_pwhash_OPSLIMIT_MAX crypto_pwhash_argon2i_OPSLIMIT_MAX -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_max(void); - -#define crypto_pwhash_MEMLIMIT_MIN crypto_pwhash_argon2i_MEMLIMIT_MIN -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_min(void); - -#define crypto_pwhash_MEMLIMIT_MAX crypto_pwhash_argon2i_MEMLIMIT_MAX -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_max(void); - -#define crypto_pwhash_OPSLIMIT_INTERACTIVE crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_interactive(void); - -#define crypto_pwhash_MEMLIMIT_INTERACTIVE crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_interactive(void); - -#define crypto_pwhash_OPSLIMIT_MODERATE crypto_pwhash_argon2i_OPSLIMIT_MODERATE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_moderate(void); - -#define crypto_pwhash_MEMLIMIT_MODERATE crypto_pwhash_argon2i_MEMLIMIT_MODERATE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_moderate(void); - -#define crypto_pwhash_OPSLIMIT_SENSITIVE crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_sensitive(void); - -#define crypto_pwhash_MEMLIMIT_SENSITIVE crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_sensitive(void); - -/* - * With this function, do not forget to store all parameters, including the - * algorithm identifier in order to produce deterministic output. - */ -SODIUM_EXPORT -int crypto_pwhash(unsigned char * const out, unsigned long long outlen, - const char * const passwd, unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, int alg) - __attribute__ ((warn_unused_result)); - -/* - * The output string already includes all the required parameters, including - * the algorithm identifier. The string is all that has to be stored in - * order to verify a password. - */ -SODIUM_EXPORT -int crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], - const char * const passwd, unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_str_verify(const char str[crypto_pwhash_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -#define crypto_pwhash_PRIMITIVE "argon2i" -SODIUM_EXPORT -const char *crypto_pwhash_primitive(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h deleted file mode 100644 index fed965878..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef crypto_pwhash_argon2i_H -#define crypto_pwhash_argon2i_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_argon2i_ALG_ARGON2I13 1 -SODIUM_EXPORT -int crypto_pwhash_argon2i_alg_argon2i13(void); - -#define crypto_pwhash_argon2i_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_bytes_min(void); - -#define crypto_pwhash_argon2i_BYTES_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_bytes_max(void); - -#define crypto_pwhash_argon2i_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_passwd_min(void); - -#define crypto_pwhash_argon2i_PASSWD_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_passwd_max(void); - -#define crypto_pwhash_argon2i_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_saltbytes(void); - -#define crypto_pwhash_argon2i_STRBYTES 128U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_strbytes(void); - -#define crypto_pwhash_argon2i_STRPREFIX "$argon2i$" -SODIUM_EXPORT -const char *crypto_pwhash_argon2i_strprefix(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MIN 3U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_min(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_max(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MIN 8192U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_min(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MAX ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_max(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE 4U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_interactive(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE 33554432U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_interactive(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MODERATE 6U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_moderate(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MODERATE 134217728U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_moderate(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE 8U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_sensitive(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE 536870912U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_argon2i(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, - int alg) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h deleted file mode 100644 index 550fd6fd5..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_argon2id.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef crypto_pwhash_argon2id_H -#define crypto_pwhash_argon2id_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_argon2id_ALG_ARGON2ID13 2 -SODIUM_EXPORT -int crypto_pwhash_argon2id_alg_argon2id13(void); - -#define crypto_pwhash_argon2id_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_bytes_min(void); - -#define crypto_pwhash_argon2id_BYTES_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_bytes_max(void); - -#define crypto_pwhash_argon2id_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_passwd_min(void); - -#define crypto_pwhash_argon2id_PASSWD_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_passwd_max(void); - -#define crypto_pwhash_argon2id_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_saltbytes(void); - -#define crypto_pwhash_argon2id_STRBYTES 128U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_strbytes(void); - -#define crypto_pwhash_argon2id_STRPREFIX "$argon2id$" -SODIUM_EXPORT -const char *crypto_pwhash_argon2id_strprefix(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MIN 1U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_min(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_max(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MIN 8192U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_min(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MAX ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_max(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE 2U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_interactive(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE 67108864U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_interactive(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MODERATE 3U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_moderate(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MODERATE 268435456U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_moderate(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE 4U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_sensitive(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE 1073741824U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_argon2id(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, - int alg) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h deleted file mode 100644 index 987f123fb..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef crypto_pwhash_scryptsalsa208sha256_H -#define crypto_pwhash_scryptsalsa208sha256_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_scryptsalsa208sha256_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_bytes_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_BYTES_MAX (SIZE_MAX > 0x1fffffffe0ULL ? 0x1fffffffe0ULL : SIZE_MAX) -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_bytes_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_passwd_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX SIZE_MAX -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_passwd_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void); - -#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void); - -#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" -SODIUM_EXPORT -const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN 32768U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN 16777216U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX ((SIZE_MAX >= 68719476736U) ? 68719476736U : SIZE_MAX) -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, - size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, - size_t memlimit) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, - const uint8_t * salt, size_t saltlen, - uint64_t N, uint32_t r, uint32_t p, - uint8_t * buf, size_t buflen) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult.h deleted file mode 100644 index 830c10f64..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef crypto_scalarmult_H -#define crypto_scalarmult_H - -#include - -#include "crypto_scalarmult_curve25519.h" -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES -SODIUM_EXPORT -size_t crypto_scalarmult_bytes(void); - -#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES -SODIUM_EXPORT -size_t crypto_scalarmult_scalarbytes(void); - -#define crypto_scalarmult_PRIMITIVE "curve25519" -SODIUM_EXPORT -const char *crypto_scalarmult_primitive(void); - -SODIUM_EXPORT -int crypto_scalarmult_base(unsigned char *q, const unsigned char *n); - -SODIUM_EXPORT -int crypto_scalarmult(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h deleted file mode 100644 index d96840c73..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef crypto_scalarmult_curve25519_H -#define crypto_scalarmult_curve25519_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_curve25519_BYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_curve25519_bytes(void); - -#define crypto_scalarmult_curve25519_SCALARBYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_curve25519_scalarbytes(void); - -SODIUM_EXPORT -int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox.h deleted file mode 100644 index 9b098200e..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef crypto_secretbox_H -#define crypto_secretbox_H - -#include - -#include "crypto_secretbox_xsalsa20poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES -SODIUM_EXPORT -size_t crypto_secretbox_keybytes(void); - -#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES -SODIUM_EXPORT -size_t crypto_secretbox_noncebytes(void); - -#define crypto_secretbox_MACBYTES crypto_secretbox_xsalsa20poly1305_MACBYTES -SODIUM_EXPORT -size_t crypto_secretbox_macbytes(void); - -#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" -SODIUM_EXPORT -const char *crypto_secretbox_primitive(void); - -SODIUM_EXPORT -int crypto_secretbox_easy(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_secretbox_detached(unsigned char *c, unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_secretbox_keygen(unsigned char k[crypto_secretbox_KEYBYTES]); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES -SODIUM_EXPORT -size_t crypto_secretbox_zerobytes(void); - -#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES -SODIUM_EXPORT -size_t crypto_secretbox_boxzerobytes(void); - -SODIUM_EXPORT -int crypto_secretbox(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h deleted file mode 100644 index 7a61a0917..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef crypto_secretbox_xchacha20poly1305_H -#define crypto_secretbox_xchacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_xchacha20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_keybytes(void); - -#define crypto_secretbox_xchacha20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_noncebytes(void); - -#define crypto_secretbox_xchacha20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_macbytes(void); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_easy(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_open_easy(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_detached(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h deleted file mode 100644 index 5aa30805d..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef crypto_secretbox_xsalsa20poly1305_H -#define crypto_secretbox_xsalsa20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_xsalsa20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_keybytes(void); - -#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_noncebytes(void); - -#define crypto_secretbox_xsalsa20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_macbytes(void); - -#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_boxzerobytes(void); - -#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES \ - (crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES + \ - crypto_secretbox_xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_zerobytes(void); - -SODIUM_EXPORT -int crypto_secretbox_xsalsa20poly1305(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_secretbox_xsalsa20poly1305_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -void crypto_secretbox_xsalsa20poly1305_keygen(unsigned char k[crypto_secretbox_xsalsa20poly1305_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash.h deleted file mode 100644 index a49880824..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef crypto_shorthash_H -#define crypto_shorthash_H - -#include - -#include "crypto_shorthash_siphash24.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_shorthash_BYTES crypto_shorthash_siphash24_BYTES -SODIUM_EXPORT -size_t crypto_shorthash_bytes(void); - -#define crypto_shorthash_KEYBYTES crypto_shorthash_siphash24_KEYBYTES -SODIUM_EXPORT -size_t crypto_shorthash_keybytes(void); - -#define crypto_shorthash_PRIMITIVE "siphash24" -SODIUM_EXPORT -const char *crypto_shorthash_primitive(void); - -SODIUM_EXPORT -int crypto_shorthash(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -SODIUM_EXPORT -void crypto_shorthash_keygen(unsigned char k[crypto_shorthash_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h deleted file mode 100644 index 745ed48fa..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef crypto_shorthash_siphash24_H -#define crypto_shorthash_siphash24_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -/* -- 64-bit output -- */ - -#define crypto_shorthash_siphash24_BYTES 8U -SODIUM_EXPORT -size_t crypto_shorthash_siphash24_bytes(void); - -#define crypto_shorthash_siphash24_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphash24_keybytes(void); - -SODIUM_EXPORT -int crypto_shorthash_siphash24(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); - -#ifndef SODIUM_LIBRARY_MINIMAL -/* -- 128-bit output -- */ - -#define crypto_shorthash_siphashx24_BYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphashx24_bytes(void); - -#define crypto_shorthash_siphashx24_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphashx24_keybytes(void); - -SODIUM_EXPORT -int crypto_shorthash_siphashx24(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign.h deleted file mode 100644 index b0335bf27..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef crypto_sign_H -#define crypto_sign_H - -/* - * THREAD SAFETY: crypto_sign_keypair() is thread-safe, - * provided that sodium_init() was called before. - * - * Other functions, including crypto_sign_seed_keypair() are always thread-safe. - */ - -#include - -#include "crypto_sign_ed25519.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef crypto_sign_ed25519ph_state crypto_sign_state; - -SODIUM_EXPORT -size_t crypto_sign_statebytes(void); - -#define crypto_sign_BYTES crypto_sign_ed25519_BYTES -SODIUM_EXPORT -size_t crypto_sign_bytes(void); - -#define crypto_sign_SEEDBYTES crypto_sign_ed25519_SEEDBYTES -SODIUM_EXPORT -size_t crypto_sign_seedbytes(void); - -#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES -SODIUM_EXPORT -size_t crypto_sign_publickeybytes(void); - -#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES -SODIUM_EXPORT -size_t crypto_sign_secretkeybytes(void); - -#define crypto_sign_PRIMITIVE "ed25519" -SODIUM_EXPORT -const char *crypto_sign_primitive(void); - -SODIUM_EXPORT -int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_sign_keypair(unsigned char *pk, unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign(unsigned char *sm, unsigned long long *smlen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_open(unsigned char *m, unsigned long long *mlen_p, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_detached(unsigned char *sig, unsigned long long *siglen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_verify_detached(const unsigned char *sig, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_init(crypto_sign_state *state); - -SODIUM_EXPORT -int crypto_sign_update(crypto_sign_state *state, - const unsigned char *m, unsigned long long mlen); - -SODIUM_EXPORT -int crypto_sign_final_create(crypto_sign_state *state, unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_final_verify(crypto_sign_state *state, unsigned char *sig, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_ed25519.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_ed25519.h deleted file mode 100644 index 17c150f28..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_ed25519.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef crypto_sign_ed25519_H -#define crypto_sign_ed25519_H - -#include -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_sign_ed25519ph_state { - crypto_hash_sha512_state hs; -} crypto_sign_ed25519ph_state; - -SODIUM_EXPORT -size_t crypto_sign_ed25519ph_statebytes(void); - -#define crypto_sign_ed25519_BYTES 64U -SODIUM_EXPORT -size_t crypto_sign_ed25519_bytes(void); - -#define crypto_sign_ed25519_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_sign_ed25519_seedbytes(void); - -#define crypto_sign_ed25519_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_sign_ed25519_publickeybytes(void); - -#define crypto_sign_ed25519_SECRETKEYBYTES (32U + 32U) -SODIUM_EXPORT -size_t crypto_sign_ed25519_secretkeybytes(void); - -SODIUM_EXPORT -int crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen_p, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_ed25519_detached(unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_verify_detached(const unsigned char *sig, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_ed25519_keypair(unsigned char *pk, unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed); - -SODIUM_EXPORT -int crypto_sign_ed25519_pk_to_curve25519(unsigned char *curve25519_pk, - const unsigned char *ed25519_pk) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_curve25519(unsigned char *curve25519_sk, - const unsigned char *ed25519_sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_seed(unsigned char *seed, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_init(crypto_sign_ed25519ph_state *state); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_update(crypto_sign_ed25519ph_state *state, - const unsigned char *m, - unsigned long long mlen); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_final_create(crypto_sign_ed25519ph_state *state, - unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *sk); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_final_verify(crypto_sign_ed25519ph_state *state, - unsigned char *sig, - const unsigned char *pk) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h deleted file mode 100644 index 2224a94e0..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_sign_edwards25519sha512batch.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef crypto_sign_edwards25519sha512batch_H -#define crypto_sign_edwards25519sha512batch_H - -/* - * WARNING: This construction was a prototype, which should not be used - * any more in new projects. - * - * crypto_sign_edwards25519sha512batch is provided for applications - * initially built with NaCl, but as recommended by the author of this - * construction, new applications should use ed25519 instead. - * - * In Sodium, you should use the high-level crypto_sign_*() functions instead. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_sign_edwards25519sha512batch_BYTES 64U -#define crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES 32U -#define crypto_sign_edwards25519sha512batch_SECRETKEYBYTES (32U + 32U) - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch(unsigned char *sm, - unsigned long long *smlen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *sk) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch_open(unsigned char *m, - unsigned long long *mlen_p, - const unsigned char *sm, - unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch_keypair(unsigned char *pk, - unsigned char *sk) - __attribute__ ((deprecated)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream.h deleted file mode 100644 index 22de6ff52..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef crypto_stream_H -#define crypto_stream_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include - -#include "crypto_stream_xsalsa20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES -SODIUM_EXPORT -size_t crypto_stream_keybytes(void); - -#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES -SODIUM_EXPORT -size_t crypto_stream_noncebytes(void); - -#define crypto_stream_PRIMITIVE "xsalsa20" -SODIUM_EXPORT -const char *crypto_stream_primitive(void); - -SODIUM_EXPORT -int crypto_stream(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_keygen(unsigned char k[crypto_stream_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h deleted file mode 100644 index 33ee1b897..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_aes128ctr.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef crypto_stream_aes128ctr_H -#define crypto_stream_aes128ctr_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_aes128ctr_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_stream_aes128ctr_keybytes(void); - -#define crypto_stream_aes128ctr_NONCEBYTES 16U -SODIUM_EXPORT -size_t crypto_stream_aes128ctr_noncebytes(void); - -#define crypto_stream_aes128ctr_BEFORENMBYTES 1408U -SODIUM_EXPORT -size_t crypto_stream_aes128ctr_beforenmbytes(void); - -SODIUM_EXPORT -int crypto_stream_aes128ctr(unsigned char *out, unsigned long long outlen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_xor(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_beforenm(unsigned char *c, const unsigned char *k) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_afternm(unsigned char *out, unsigned long long len, - const unsigned char *nonce, const unsigned char *c) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_aes128ctr_xor_afternm(unsigned char *out, const unsigned char *in, - unsigned long long len, - const unsigned char *nonce, - const unsigned char *c) - __attribute__ ((deprecated)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_chacha20.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_chacha20.h deleted file mode 100644 index 352b92904..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_chacha20.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef crypto_stream_chacha20_H -#define crypto_stream_chacha20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_chacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_chacha20_keybytes(void); - -#define crypto_stream_chacha20_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_chacha20_noncebytes(void); - -/* ChaCha20 with a 64-bit nonce and a 64-bit counter, as originally designed */ - -SODIUM_EXPORT -int crypto_stream_chacha20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_chacha20_keygen(unsigned char k[crypto_stream_chacha20_KEYBYTES]); - -/* ChaCha20 with a 96-bit nonce and a 32-bit counter (IETF) */ - -#define crypto_stream_chacha20_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_chacha20_ietf_keybytes(void); - -#define crypto_stream_chacha20_ietf_NONCEBYTES 12U -SODIUM_EXPORT -size_t crypto_stream_chacha20_ietf_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint32_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_chacha20_ietf_keygen(unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]); - -/* Aliases */ - -#define crypto_stream_chacha20_IETF_KEYBYTES crypto_stream_chacha20_ietf_KEYBYTES -#define crypto_stream_chacha20_IETF_NONCEBYTES crypto_stream_chacha20_ietf_NONCEBYTES - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa20.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa20.h deleted file mode 100644 index 961e5c1c5..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa20.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_stream_salsa20_H -#define crypto_stream_salsa20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa20_keybytes(void); - -#define crypto_stream_salsa20_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa20_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_salsa20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_salsa20_keygen(unsigned char k[crypto_stream_salsa20_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h deleted file mode 100644 index d5c442821..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef crypto_stream_salsa2012_H -#define crypto_stream_salsa2012_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa2012_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa2012_keybytes(void); - -#define crypto_stream_salsa2012_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa2012_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_salsa2012(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_salsa2012_keygen(unsigned char k[crypto_stream_salsa2012_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa208.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa208.h deleted file mode 100644 index 02b4166e1..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_salsa208.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef crypto_stream_salsa208_H -#define crypto_stream_salsa208_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa208_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa208_keybytes(void); - -#define crypto_stream_salsa208_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa208_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_salsa208(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_salsa208_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_salsa208_keygen(unsigned char k[crypto_stream_salsa208_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h deleted file mode 100644 index f884798e7..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_stream_xchacha20_H -#define crypto_stream_xchacha20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_xchacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_xchacha20_keybytes(void); - -#define crypto_stream_xchacha20_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_stream_xchacha20_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_xchacha20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xchacha20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xchacha20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_xchacha20_keygen(unsigned char k[crypto_stream_xchacha20_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h deleted file mode 100644 index ed5ae3c3d..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_stream_xsalsa20_H -#define crypto_stream_xsalsa20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_xsalsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_xsalsa20_keybytes(void); - -#define crypto_stream_xsalsa20_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_stream_xsalsa20_noncebytes(void); - -SODIUM_EXPORT -int crypto_stream_xsalsa20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xsalsa20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k); - -SODIUM_EXPORT -int crypto_stream_xsalsa20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k); - -SODIUM_EXPORT -void crypto_stream_xsalsa20_keygen(unsigned char k[crypto_stream_xsalsa20_KEYBYTES]); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_16.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_16.h deleted file mode 100644 index 5e9eeabee..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_16.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_16_H -#define crypto_verify_16_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_16_BYTES 16U -SODIUM_EXPORT -size_t crypto_verify_16_bytes(void); - -SODIUM_EXPORT -int crypto_verify_16(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_32.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_32.h deleted file mode 100644 index 281b5a1bb..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_32.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_32_H -#define crypto_verify_32_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_32_BYTES 32U -SODIUM_EXPORT -size_t crypto_verify_32_bytes(void); - -SODIUM_EXPORT -int crypto_verify_32(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_64.h b/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_64.h deleted file mode 100644 index 0dc7c304a..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/crypto_verify_64.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_64_H -#define crypto_verify_64_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_64_BYTES 64U -SODIUM_EXPORT -size_t crypto_verify_64_bytes(void); - -SODIUM_EXPORT -int crypto_verify_64(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/export.h b/src/Native/libubqhash/windows/include/libsodium/sodium/export.h deleted file mode 100644 index c33bced81..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/export.h +++ /dev/null @@ -1,44 +0,0 @@ - -#ifndef sodium_export_H -#define sodium_export_H - -#ifndef __GNUC__ -# ifdef __attribute__ -# undef __attribute__ -# endif -# define __attribute__(a) -#endif - -#ifdef SODIUM_STATIC -# define SODIUM_EXPORT -#else -# if defined(_MSC_VER) -# ifdef SODIUM_DLL_EXPORT -# define SODIUM_EXPORT __declspec(dllexport) -# else -# define SODIUM_EXPORT __declspec(dllimport) -# endif -# else -# if defined(__SUNPRO_C) -# ifndef __GNU_C__ -# define SODIUM_EXPORT __attribute__ (visibility(__global)) -# else -# define SODIUM_EXPORT __attribute__ __global -# endif -# elif defined(_MSG_VER) -# define SODIUM_EXPORT extern __declspec(dllexport) -# else -# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) -# endif -# endif -#endif - -#ifndef CRYPTO_ALIGN -# if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# define CRYPTO_ALIGN(x) __declspec(align(x)) -# else -# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) -# endif -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes.h b/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes.h deleted file mode 100644 index d112fb293..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes.h +++ /dev/null @@ -1,66 +0,0 @@ - -#ifndef randombytes_H -#define randombytes_H - -#include -#include - -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct randombytes_implementation { - const char *(*implementation_name)(void); /* required */ - uint32_t (*random)(void); /* required */ - void (*stir)(void); /* optional */ - uint32_t (*uniform)(const uint32_t upper_bound); /* optional, a default implementation will be used if NULL */ - void (*buf)(void * const buf, const size_t size); /* required */ - int (*close)(void); /* optional */ -} randombytes_implementation; - -#define randombytes_SEEDBYTES 32U -SODIUM_EXPORT -size_t randombytes_seedbytes(void); - -SODIUM_EXPORT -void randombytes_buf(void * const buf, const size_t size); - -SODIUM_EXPORT -void randombytes_buf_deterministic(void * const buf, const size_t size, - const unsigned char seed[randombytes_SEEDBYTES]); - -SODIUM_EXPORT -uint32_t randombytes_random(void); - -SODIUM_EXPORT -uint32_t randombytes_uniform(const uint32_t upper_bound); - -SODIUM_EXPORT -void randombytes_stir(void); - -SODIUM_EXPORT -int randombytes_close(void); - -SODIUM_EXPORT -int randombytes_set_implementation(randombytes_implementation *impl); - -SODIUM_EXPORT -const char *randombytes_implementation_name(void); - -/* -- NaCl compatibility interface -- */ - -SODIUM_EXPORT -void randombytes(unsigned char * const buf, const unsigned long long buf_len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_salsa20_random.h b/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_salsa20_random.h deleted file mode 100644 index 4deae15b6..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_salsa20_random.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef randombytes_salsa20_random_H -#define randombytes_salsa20_random_H - -#include "export.h" -#include "randombytes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -extern struct randombytes_implementation randombytes_salsa20_implementation; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_sysrandom.h b/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_sysrandom.h deleted file mode 100644 index 9e27b674c..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/randombytes_sysrandom.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef randombytes_sysrandom_H -#define randombytes_sysrandom_H - -#include "export.h" -#include "randombytes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -extern struct randombytes_implementation randombytes_sysrandom_implementation; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/runtime.h b/src/Native/libubqhash/windows/include/libsodium/sodium/runtime.h deleted file mode 100644 index 76859ea0e..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/runtime.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef sodium_runtime_H -#define sodium_runtime_H - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -int sodium_runtime_has_neon(void); - -SODIUM_EXPORT -int sodium_runtime_has_sse2(void); - -SODIUM_EXPORT -int sodium_runtime_has_sse3(void); - -SODIUM_EXPORT -int sodium_runtime_has_ssse3(void); - -SODIUM_EXPORT -int sodium_runtime_has_sse41(void); - -SODIUM_EXPORT -int sodium_runtime_has_avx(void); - -SODIUM_EXPORT -int sodium_runtime_has_avx2(void); - -SODIUM_EXPORT -int sodium_runtime_has_pclmul(void); - -SODIUM_EXPORT -int sodium_runtime_has_aesni(void); - -/* ------------------------------------------------------------------------- */ - -int _sodium_runtime_get_cpu_features(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/utils.h b/src/Native/libubqhash/windows/include/libsodium/sodium/utils.h deleted file mode 100644 index 0a7aadb43..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/utils.h +++ /dev/null @@ -1,131 +0,0 @@ - -#ifndef sodium_utils_H -#define sodium_utils_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef SODIUM_C99 -# if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L -# define SODIUM_C99(X) -# else -# define SODIUM_C99(X) X -# endif -#endif - -SODIUM_EXPORT -void sodium_memzero(void * const pnt, const size_t len); - -/* - * WARNING: sodium_memcmp() must be used to verify if two secret keys - * are equal, in constant time. - * It returns 0 if the keys are equal, and -1 if they differ. - * This function is not designed for lexicographical comparisons. - */ -SODIUM_EXPORT -int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len) - __attribute__ ((warn_unused_result)); - -/* - * sodium_compare() returns -1 if b1_ < b2_, 1 if b1_ > b2_ and 0 if b1_ == b2_ - * It is suitable for lexicographical comparisons, or to compare nonces - * and counters stored in little-endian format. - * However, it is slower than sodium_memcmp(). - */ -SODIUM_EXPORT -int sodium_compare(const unsigned char *b1_, const unsigned char *b2_, - size_t len) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int sodium_is_zero(const unsigned char *n, const size_t nlen); - -SODIUM_EXPORT -void sodium_increment(unsigned char *n, const size_t nlen); - -SODIUM_EXPORT -void sodium_add(unsigned char *a, const unsigned char *b, const size_t len); - -SODIUM_EXPORT -char *sodium_bin2hex(char * const hex, const size_t hex_maxlen, - const unsigned char * const bin, const size_t bin_len); - -SODIUM_EXPORT -int sodium_hex2bin(unsigned char * const bin, const size_t bin_maxlen, - const char * const hex, const size_t hex_len, - const char * const ignore, size_t * const bin_len, - const char ** const hex_end); - -SODIUM_EXPORT -int sodium_mlock(void * const addr, const size_t len); - -SODIUM_EXPORT -int sodium_munlock(void * const addr, const size_t len); - -/* WARNING: sodium_malloc() and sodium_allocarray() are not general-purpose - * allocation functions. - * - * They return a pointer to a region filled with 0xd0 bytes, immediately - * followed by a guard page. - * As a result, accessing a single byte after the requested allocation size - * will intentionally trigger a segmentation fault. - * - * A canary and an additional guard page placed before the beginning of the - * region may also kill the process if a buffer underflow is detected. - * - * The memory layout is: - * [unprotected region size (read only)][guard page (no access)][unprotected pages (read/write)][guard page (no access)] - * With the layout of the unprotected pages being: - * [optional padding][16-bytes canary][user region] - * - * However: - * - These functions are significantly slower than standard functions - * - Each allocation requires 3 or 4 additional pages - * - The returned address will not be aligned if the allocation size is not - * a multiple of the required alignment. For this reason, these functions - * are designed to store data, such as secret keys and messages. - * - * sodium_malloc() can be used to allocate any libsodium data structure. - * - * The crypto_generichash_state structure is packed and its length is - * either 357 or 361 bytes. For this reason, when using sodium_malloc() to - * allocate a crypto_generichash_state structure, padding must be added in - * order to ensure proper alignment. crypto_generichash_statebytes() - * returns the rounded up structure size, and should be prefered to sizeof(): - * state = sodium_malloc(crypto_generichash_statebytes()); - */ - -SODIUM_EXPORT -void *sodium_malloc(const size_t size) - __attribute__ ((malloc)); - -SODIUM_EXPORT -void *sodium_allocarray(size_t count, size_t size) - __attribute__ ((malloc)); - -SODIUM_EXPORT -void sodium_free(void *ptr); - -SODIUM_EXPORT -int sodium_mprotect_noaccess(void *ptr); - -SODIUM_EXPORT -int sodium_mprotect_readonly(void *ptr); - -SODIUM_EXPORT -int sodium_mprotect_readwrite(void *ptr); - -/* -------- */ - -int _sodium_alloc_init(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/include/libsodium/sodium/version.h b/src/Native/libubqhash/windows/include/libsodium/sodium/version.h deleted file mode 100644 index ab8839f79..000000000 --- a/src/Native/libubqhash/windows/include/libsodium/sodium/version.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef sodium_version_H -#define sodium_version_H - -#include "export.h" - -#define SODIUM_VERSION_STRING "1.0.13" - -#define SODIUM_LIBRARY_VERSION_MAJOR 9 -#define SODIUM_LIBRARY_VERSION_MINOR 5 - - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -const char *sodium_version_string(void); - -SODIUM_EXPORT -int sodium_library_version_major(void); - -SODIUM_EXPORT -int sodium_library_version_minor(void); - -SODIUM_EXPORT -int sodium_library_minimal(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/Native/libubqhash/windows/lib/x64/libsodium.lib b/src/Native/libubqhash/windows/lib/x64/libsodium.lib deleted file mode 100644 index 1e9bb80b80b236113b098c5082a905f61b956656..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1885178 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

@(=2*v+<(L0X#Qy33zxidsPrbnYj~hx~ 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 Kh! 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 NM;)UYY$``j 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�A;$+Z_49janZ*~o9-u3Y$om%V{uSysl~Qh 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


FkG_dOotj56pY+$z=*fR$9f`P3y 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

iq2S8Qir zI`wTGMn>y$0alo zyS{<1fxq6~RDVdo)#A8>CSupQ!sVBTN8R zT?{k`!(Wen_xONojpGuUh+UTmS2zrH+>drV;kbk*V%McHy8^DiJ1(J#*maq372`LB zXT(dlJ*Z=zc<}}m@fQbO;EATg%ZXSzT(`&BCkI?7IxeA!*mZ?)u}+~~S8wkAOPx=_ zi+8Ex5}Js=uEf{Cu9w!nP#ADM>$rp_V%N8Xi{(ZRp0hrC@zsEGa3-hFthZCc#e z(ol6;T~qz+#Z@DQ`#^0&Q(aZ|u_$VAJ-exdiKWL&91G>f$iAgQFR!OR; zt2(Wwsil5?UAt~+9A4E<@=%8)Ai_E~EQd=b4tcS$oq+cPpsKc}c1~S835&#Kjb#Y0 zL~?!7_TviSGizo$DNS9PglvAhIRvuix0^*kltfSxInA{-^JFeJ3XFBB45VB`tKOYM_Tw$dgP z9Mo6|rH2@jTj5uA$?Y(XgqBDJmr%UYCKSx1nNY5fCKSueolvZhCKSu6H=$S|O(>SN zbwaU1nouk%_=HkPnONxXJ7kH^lhh)=S()4~A&!n(G9qz+`IdkqsU_O#O&VB^I;rpx(xgr*+)*bK zE-mbYqLntO;G`8U$|h;SCk^YQ?E}b7+&%zp2b`O@eL%56!(aLf34=PumN3+_cQ+DR z+=hVKIW_eQN=n;q%friUh|tP#i$tg^%C_7UTO=Z3bcCYO@Af5(hfJJFEDd^rNh}Ic zClv1bjtPbP)K0jrI&{45#kZGB3w^0#b|09B^gJ;4H2}iBRPCSU4J#WlvUGT{sj^X} zBSwrZ9X)E4L1HK?E!}(Xy^D*>Mvf^RAxL%JtZxkQ25!FkxT>${OeaS}!@CjrJ`B$X zooNaw+|d$VXUs33ZsTA470{J?h2tFEkv_TvhF#t21s@Z-(9T5S91XuZMps@Q-b+S0 z&J*H*a&K?927sf|#f8(V)7`fb?wbReN;d;K0CeSra9?OoA|M%`zNP?&rsJXF%uptI zT)}-4Xiji5J`|ftUIXwqL36a5L19p4lJ_*^T@0GpZe*JN&m@ohowvhJNM(}u5WaT@ z-IIWEhU42Cpy}I3$UFplM*nj6$Pmz+9VE2 z*ANgFfo9<@O4nBU`^B!9SH(k>E&bhz4;w&pet)IQmj3A9zO*c)GWqu*eBT9huQ=Ll z{-wOUfgxcqW|LP4I_}P($|mnjeESqMrA7~zJM;`t0x}$+nR5t&<2fEMN zk;i!75%txcc&OS6zfqv6aCCn7q3Rnpe!|3xqb46YdD6Ij2H@wQDMt>7f>S4tKdfTP zgd+wNGaBE+^J6@Vyp$C72kkSXrJ-S7^Njh;i<|czIb%-4{JI(Q>uZ}DW;8d|&X|Wo z+ZtxoFPuN4Vdg2Jw?!a592GmZ#m_jcY-HJt<`$f$SvzB9!=lgxC~>%W4$nSY)5)-BZKG_Nq^zwapE)TZ#uCzDM!YMoj6{pHaWyOMTEkaK7nwsm+z<7uJsboTrbd6Q;)Cbk_~d|f{qB6{Hv_KiilY-i-$+Yp z_nFby)NpcB&HUoo@Jn;?;6-Eh-eU#_<+(YIMrgH>8HV#ZK8ith4w11kn-FBZHKIVZpZh7S3tD7bb>+|@bLyiQ#mGgk* z85Dyvy}!Osr$kiw5l0<;Oy#o8b1HeC1DbIo9;(Dm_R}Vu})98gq@8Y<=K(cqJiYqb2FfZVN@ z4XVIBvJ!iQ$&;>%NM;Z5qM;RY}Fv%8OZ!R*%c)2>WCr&ZW z!PnQ}?lR76}!l=8w|U}uzL*qsbL!od(klFRh75dFrI0o829GVgj-z=fbRMpIGscTv=U-N9JDDijAvPYb~sK6O~$iHbtLr@fi zS+yt#vVQoRW-aFOOgTOe*^MEwSCM8j`YwYi=MD8mMP2bJoV5!1jvqg3^~HNy)+#m< zI#_{C&Yp2d|bwYQoK!2OeetVx;WU`? z1ml;Z#Z-siXia&#I6hiaHh_wD&%ncyS5?AfKC^B%+JcdEJ{O6tqKLU#>#-wHb+U90 zSDQPAs+myzq*m`1`snJQN=Rb@V*{O%f~?S2a*@^~%~F#TgKAqOZ6=|q56wy+JHwgsyl)zI zfnnDhc9UTb8TOcAPaC$uFrFL6l$P(!ai%32gcsp??L(>0)NA7`yc$4g^q>f|9s_&Pf&E-Ta2$#;8m``^)0{QvGAp6;1^d(wc8J0nR;`X zeq~p5PyzGAiS!DXDL)SntCdX*TTuzq$K1NbjWzX6@P^-(cLhyQ0~bnJ!Unkt-#J9= z3LX|?J;Yi)@I7eF^MZ9PWCnt}pDSdF)s5-Ds6*M5ECsFwiz`UR7y$dMEmp{(cS0=D#XCdC!;{Eb8Aip>_j2zn9S+B%u}G7a4vMjKQ0yB<_f5mr7{+o!>FzM> zF2mTuQ+Yg#N$H|_U=e7KY$FeRrK5RZeogJxO#evDt#BfDzDWAN96Cd8G9C>%nozzO zw#u1MzV(ICayvux=r(-1dq;hW<><9_N&Tt~DW(%&Wh&dwcD`Nae0z@b?V(^&-_oSH zT`}f%#r_Kh3XXzf+a4%rMVnw+S|qIi7h`fEo?@{5 zRUIfsGK?5#aT2sw!d?6H;vzg^V8uhwO$xJa`G~;~RAz0rxT7Nmn!Ok*+Ktle#Zs5e z77W(;gK@=1l5NC**=H~wUoqTE@gUA@z@Qx20k2+#%NDE{G+WS=Cnpmq#<66@nD7<5 z%CH|9#!)h*`>kQm81{)_pBcs;k;-F_NO_|@BHDd?T4lsqn~J_FK_IJ2n2H*)L8QJG z?cS~1YG`z!c`9_e3x$dlHkB}IsM4f8BE_!6yJ8*lvA+))79<;F!`>2%HE(qvqp)m+ z7rfJ*j~6)~PXeYsrb&IQ7=5f5dqu_U6*Wc&hN@*?2s0|rVN9q(!bL`iHi6SC7%U?| zlS_&V24i~V-g06^T?&e(7RvX~bP5NCs%;2q#Wf`o*vlSjta_0B6g2I;T(1nj$B1b< zeoqt=J6^|$sUE-4VWD#}6liCHsvn+eJb&tFf!17CH>)aZ4~z|@0T9a`Uvyk(0K(Vr zuDKpq&?4H^x@+k0K%F3iq%2WV9xas594SKo2&$jF2SwmcLcUqNGN-0_jtv(14Ta014iuEwZa_f*DW_d28i6m1Y}Q5iA&kKCj`}n^j^^Sf!-TBi<#}AS3~auooxc908O+s<$08;*jdh$ zCv6bLFc2VL^JI2ev6~IM+jxIs*zXN{!LTtQhVxt~vvsDSOp|t@6k``kG0F7SVQkO0gFEWmj*Jb# zO{_?nwtU4j#`hdNB@RR~Zl&=&=UWUBNSZnfnEI9`^{ry`tz!N9cJjJC(5W%EI%k@H zmCH1IEyQyY9@?X=UoqgP8joK0pr)>PKUuJj%c?P1YND+9Dytta%L z58T8Y;;Wf3sGHP8In9El(k}KH?z2Fz6^dLlk&E%2O(UW6Pj7xmMR9^n{v z59&hyTuMQAnx_S3T-ix-x|c2^MZnf+BPH0$x}$GaX;7?#stXxa`R#!@ui zgX0Is;Tu(OWOS1PX!I3J+QxBZ4hfE)e$gTMMpFpiQuQ*V!XZV5G&-b*A!{7c-;m!q zghv@8fkA!Zkl>K*68(Tdd!ObQhZGp{b%%5_@+ChUqj@HVycR?L7C~@CGaIg=m>%`eT?fciv>+pWgsC@*upEnWvBZuZ z%sUW>9%__=sq1xbOb?FM>EV*5&_oW&DG@FylVLjlThq4>&iMugeGFwSMW7BgvvW|)1v{`BF7~(5xe#jE|xv?*9DCg zOFHbKIJF-&T%OR5j138C7N{ z2!(bR28*qI`ivhVr`>3(PhD4_YMqL3^VQ!l62I3 zS)M@N#h}6U1){RaE5X;FfM#O?d4C4YhiUSVhQG+ZF82Gs_T}yCYObr97cQT%(+dAv zad+2yaQ}UHcE?_=<1pOes>PG*7T_RDScQsk=DeD@b;D;?al2U^1_RpO1Xkd_FRWkC zviC^r0^2paUKO@qJ~FZEkw{(A-;( zzk2+_3tnA$5{4r7f}q0GAKtp;fpymu>~z4hzy90r7C$inTa5*e?>Bow@Qc5G#K-sc zJAYN_kE_0$KX?D9bRSw@7GeJv_o1byRN08uZgQ6GXkTPAoWF<9?VN0Esy_{>6&v{G z&u>_;HMZ^9F1Ia?%=tC*<~7v9P0V|&Hn?AI0P-G--c0-DjsX5;@0XM5TyBwDy7^rs z=gO7yF#Edfb*%B1&ZTUZ`+6(BOj_}=EQ5V-!ie=Fo~m3q#jCi7bcWPjDRgGDLXvfI~Wuh-@iaz;eBDFmVhoSN17zq%N21 zg5;XoTkaes#5g{F@)iAPW|1~^2+n1$PnR^uJi5drOpnR5| zB8n}4Lf3x}Zv+^Q?-fPd^fnweaXyXP$aGG(ac-G><#h2d`8r$PgBjsr5o(n+1=Q^E zd)}!+Jq_=whREbHOLNTOw4enup@_?g0`)aao*rMs+Q1jY*T%dRHX%l+>8UdX$3_& z1x1Itr54zXGiUOOhq;Y)aOKKFizkz!^1LP7)T;UN-eOt@c#hlAYCx%2cduq-u*oa; zyPmI3^tZe&eTaULU9W8Zj>VJfjlwTEbG;h;GC*?Wo(xVVPTm*T04-ZkxKmB9PEsx#n@Rcxh+_%R^sw*O045%pzPb- z`U@>f0eTFFB*;XLiV8)Rv10JI zwGKFjb6e@Lq0qkt9ff@BI_QwsdKYw539XEV5ztwr?}SGSESmCUB3`l6-Pb%>0HxTu zhF#)J`Q88@a>dOhtKkxBgG^fXacQ&c%pWpk#r;wiZo+qO z^2&oZR-QMH1=|tD(zIdeR$95@3Hi*mWtG<0SoYAdwl9Aym~(Nrsb4P5fQdc!T(2I# z(UK<@?oHnb!CpMewrV`PB1x(0NXet4TtV@ZzBX1j;k~iQhrmailQUs)90SXii=Ba&^jyV|q+(a3_zUH#VO+hSCKMXqEG}Xl#J1H7#H0g3N#aQVo)^C^2UiTE1c7zs;F(wP~ zFgem5&tq-lt3fd60x30h#XHjy7FluW+4sVdG$lr5F+KW<<$}sm6J?<`qO3i-cm*RT zcm=5gysnL1syk0p9u9g`!&r`|H=e+atMTTm0WhdsHBm0xd0*xtE{+gKRiZ^)p>bgf z$VsinFJrl``{kQ-5GlO;iSe70;;3*>n5c3k9fp^AkUJ;EIHSM+QFY|>xEyw5a#9=( zW_?1{IVOkPIVr{$UG~wCnU<AHso!GbTwp`lrPAa!;LYjd?cune55`` zv&bR2UNKS~)lD&)pG1)G@(jjcbfE>~BD&C`JCIhVc^r4|3!3tsR36)WncTN8 z@UCdeAH?Q7R5p2Z-xSbPaHJlJ!IMeeaNvIf&F;l8K(PwR-nSTOp+Bj##?2&; z=_7xDkl0TqdF%1D2z0-7wAtd9@;*r@?{m=oe4tvJO&-(Bo1j@%qIB8P%YH~NKLX8r z7+j)iE4|D|x1fn#1E_5A@i9Iu0Zj`ArKqyykBRu!dkA)J;-ShWZ^$+n4+G7rp-Pu6 zz3hk2$D*roDITh9^60+rfadZtrOTFH7$1i)(S%f{_IGemP@p&j{Zg6zj;`cT9_XW`Wd~cPPEk5YJs?kd0|7LREdVH({-Jmf_ zW$sH`f6*JCr+}u$(J?->5vn$sN}lB3e4$z!YYGDicWsBH4S3%Xm{k;kg&@r3ez z2f9BdkoQ?ad7Ur}Sj3?~sBHf2i*Lg~bFiapEBvN|=EMZ@&IHXR3FLhnG&i&(kLl=9 z(EL7uyq7`qc02MIANgoMgjKfq?FG7B9c{MoqrCkS%9{YX>1p!N5c(qPb?$<-i@&_} zI-#YM>21m_KZyA~xcyW-9bSS%hGH;&;T1ONYi#0cU=D@&Olxnh6+FI{=0m~bXFYR@ zpfD9*OLK|f>p$wT^!{rPt2pNVM|xfOmFF(gH8#Ca1#S5no2|FNBlD@z|Br(@UhnExhefz>-6tKYxTTS7BgI5vlE);tP1~K>uX?jMEx7i z)Vu)>&@(k>iis`wdNEDIFUJgXu{_4}s>M`?U;WBpW6{GAw)Ac5?3J-2GXqZ-1hJ~5 z^If(MIhgMHPdiled#Fb_@5CU=pxnGuIX?OGPSr3MqqW9UlR2q0hwqTGMTcs>4DR;Pj;x10Fk&rGhNJ37_(#>t0w11NzvB0k&uii8p2X+XS67@Q zGvgd`(b8i)OpKviIb`4@F)?;d7Sl@nM$3%fqH0brGuZRp0na&jx^+0_X4SRmZQVhc z5lnmU3z68dCsWhG3Y~rBooCn6N}d=ZYwwVEuR$t5;PPsi^ij5`{m3JMt4!^j|O5xVfH_g@txIQ8BSU}=ovc)Uk??TM%XE)=|y-r%f~!IH4eF- z2@>UY>tyJYpihU6rgH14(5FB@8~Rk}3^&M=a``xzwX~o~%VovR#JghWI#a$JX`|Q` zhFxuRKQind!&p|UJeJkU`?6uL8}^=Ie>1EQsYQ8vI}>L63@b5gKf}rmV@gxrBMn<< z*kZ%ZGi;?{w;J|C!yYi~5yLhaw%IU_D5<@i#Z~`qLb;^aW@pOt{sdooppfNV!K&fA z0G*h&z>tNzub7loC2jWjMVReHOfSlUqN`JzMOFB)J1v@mq9}Y$o)tww(GzA}AX#)U zJdvr$2}-|kR@S0Pa)x+5g@mf7?C*f^V77LFlCG7eSB&?x ztV}2SS=rC1`W`xDm_)u}yfK?1&f!K?W0CD>!uWz@KUQj*{b(fW$6Qx>;Kjjm7t^_8t%4ZDMJNvd#fVHT1*1HTSB93V%l_JTea?|q@e+SYRS z&fdZ?cr;tkq-#}g|d&;ms8}=8&@{tf!9@n3$ z9U~1JW7tN+IKr-U$UbA@*=LMoAMAF~>@#?BJkyMMa5x;mTpMJXD;*=Dbr)pSzlXH6ydc7+@Kc%M#`I z6wVS%xZy0pER&Wcjx`cJJ+<22vt$6qOL_)?kXB{@6orxjj)%?+fLN9cFatW{k?+g^ zcy}3qCOuzJv9sJ)?Jg_E?y}Nd?@amLO@`fN*nNgQYuNLKy>A%DOI2P^q&u}^duP&J zB#PZ`*cZFDU^eX0YYS?{#MJyAO^};@z&-N>Ly)n<75}P|RuTTnp5P!%*OducKmURE z7BEK2olmJT44AUmvT!qfUVo$*7O4ZEW9FN~1Fa0BLD1RN;yY8+(Rj2-rAZt5ik<1c z=6Nhg6wu)Vfcg3Pt7cf+hNo&c6ecQXk zzLniCiN}zbc1rR1igu^_7H!8?e*c;C?a!TWj{v5=rAd9O7=5eQf8!8R6N*=^#3f7gK4A42NU;aHP}e|{$nVd?Mm(#n%FP^>SKj3WhoqxMIUWXuV<4E1{Y{@thqddItL&ud?Bl2An1jBijhg+3kM&W3&}^mCxY?0o||%&ak_c0qf_l^8VT zc}wuCSgSMXbuWsoGK_9eY_(ymQxyA&VUHR1E5qI}j7@iP}|u|Gwd_NQc@z( zZyY=#N51#2VK$6ZhYvw_fosoard2+y&V0p`tSV^(DpHJP=r?F_7PO|qLq6%nl^bV@ z6i=DQlB_uTSBxd~L7=qVkYM)hig0sdN0Oc43zvO0JNLDBjxG5|lBZ?o!A7Kgic)*m zJ_WNXX?(@FV^&4H+fWj+V=G?m<^Wc1T4~diC({p#EyufJtDPy|TWc69fBBm4Jz&^N zhP`Z9C!{Hr*Ug#opBb?ExjWYdSKZq*d9maFteF zn$oNBo|e+*7)jCrC8qsKJicOlGVOQ9v!4U6LWDAWuZGSHh-yT-)8B>84EP=B70~(4 z&JP``d4ne1;i%XW_f_Xf6}!?f<`Tu$8HO%`!yYy4kA}T!*gJ;()v!WDrpn`t22FY1 zSi`t?Suu_xDIMn+6ytbOJP*0?BtH)gu0$R}_LZ~=7Y0t^F5E~R`dulKD@~c~JH|$Qs?k)z4 z4Ii9^mlM)bEJK5e^=;U)MNs=^Mg;_(HCLLu|jH8T-^~-Xv%p6d#(Dmfz zB{AUV6g+w`fSS7EeW74&-77QKxYR^0rlK4#g^7sVvtfjqpql*7!>`(-CUPtlEX*-c zX!U2le9gtLn#ggkVEu4>dj1c)Yz!Z)z{;Qy&m5t^k5tRlsTSZ-+tox_D+TMgtOk>% zCd#@*Wo5WiCvXp`eboqqx<^fv@h!n5G-fK@zN*RZsq&Sfp(b)%D_EFgKOnwpfejXc5e^!BjwB;{$PIGJ==;LZZAdIFDl!;JxrIB^Vu5@-5HldSEze>ij?g4_6)~& zSeNDgA96?U|7q{up3L_V(Kpe9G_u{>Kyfo`E{1jH`-n<}hQkYfI1d!+u$)0cN(U`9^c9 zL;4wVt3y0P9*QBqk0Bq#knR0MW^%^GkmeY&EQVYhL)JtP9A-08{pr?YcwvN1&gk(r zJz~g?F{E1zL2Ert4%2m1azPB)S&*Tj4a2(w$w{$1Na5k#KAPt7;@#)`B{Y#EX9nYI zaO4c{_6fK?a$G_aIo@UunlJ5yLh)xz*X9maDX@vnwiuCSupn zh+U^V{{A}w*MW{pXd-qE6E4;)jIVQkocCdH`_So*OK2i?l}7CP*>{I63b<}_TtXAE zt1M=h)?a|VHyoGHMC@W+AA}+83b+P#A+N60!F`OObjU$iZ4J_2yo)Kg1*^(&2~ET< zX0*UA-o+GfUE#QdCSunp;qv3F?5yRZgWIB>a9lzYv1{*$U3*TwenY^O=Y$DO#4Zjo z=A^=Q1-D>LaInxs>>3lXYxu;OPX%1xa9lzII?sE=7Z39`-Uht2cgIxv9?dF$|6f~| zOvRWuF4Lh?n9{}+gZ-s#U95nUy(3p{C*<;d)FB6kRuLt%##UJ+q>qecCFJqf=OrZX z$U#~iK6%R)>m+ncWNO??$mGXeQu@fmNq&*KD6rXw){S{LUeGF-iP)N z*G!gn8h*-oZ(8WwTjHznoQ`H^AJ>c{OL5_}>hRDFAa5gD#z%l=1jiGhIQWw3ytQY5 zzX_V3VCavEVl&C(-EZA7ruZ1g1EDy~lu6!cz<-6l+8=qlMeg`&M8FVt-yPJ0?bv)s|K1Ci}Kq>DlG9Y@Cz0-?(w z?zt=_AKd$Y_wKW4cMRQc#cS7>51rcb;4S%=V&MH#gh!^k&$#BTFcm-d>Dz+G&ujWC z(>`De=T>UrRNrwJZD-%UA^!=eDMarFI1EC*` zcYKpO$p%4Rj`!W6b7|0E=*kuZ0p#d2*tHVkh8Tv6G!C zpQlJT>~zD#4r|5YVWg#v7l0n1(ouCZdeYoiDElDQ@+>V zu)Pf9ei@~kj6ACHra6;e$SvFapM578_a^LfbxY(&BG;xF(zRb_VsIe(%_D=VJu0M?tH^os48}iVRspJpJ9(0_PAlM8Meu=4-EU*up*>) zwS!AjXwr?OitS<8r$*-?M=M?Q-m#Owo1Sz0VKmOcf1WkxY}wM>QpnE1qZPTH8i!Xd z*=eP{<6X?`2(!ivO?k3_N3lhCSL}axiPOC#8 z$rxBpiuoX_!egFD9$XTT8>O%%ZATJkeC4E;q?1IJj8Z^OYBheDirTtcY$MWUPtZ{1 z#+H7OJK5c099iXPD%Frv54F)#v|pZgeI~$gahx{?iM@HaS2Vtt^(om?TX$l zHp6iVO~fu1nmMTw{E{Skx7Z@bB{UJc&_NFQD|)xs6^=`2K!@8=976Lp9=G#{I!^us zXb6&-%Fw$_1BLlGgcn=HK`@<2+f7bf_y(>o;m$7F??!L7jA#A z7TD|;PXwqk+;{aDGW?FLh(k)|(=yz5^=j7;5saDU-PjhY>V{h)@la88rg^BHVDDa- zPn*OH3LO13o+rnwy#3pr~b-1j0r+yk1+I8XzXE&L|p+o)Z!T?r3WHhF~zzpsPlvi?e! zE&TSw=Mx8D`wkweZ1U*7HJ~|*g)NkYU)nq)ljw*+LSjGJ<}LRH-NBBQ^P+mRg7N*HVf%l&~Ps^%y>&(-him?9o-+S}cQGc5F+n1UyZaDEDeHXpE{f~4n zXr}qno8jI}^Q9jOe%%$b55F__?U#PKX1C9;x^(#(TxEuIp6T8jjQLEXca%fD-W^*{Zb!D@s}uAHAX zL`?JX%jTY*GdMy_EAfj#F<=bI_wf7(74q1$q0?)CvrByro_Acs$%`CZWJ?1xP0q0G zljIn||6NCs^5m|CilS*K@Ai^l`&V5@u@Uk57d-x4P_@_|`}wcCj)Feuf@i$*3K~{& zjvxj<7F!<4Rysf8pd6Vj?S4v*HM(gYe6w} zHJB>Wim6VZ@D-D?s_+btUrgCb+4SOy?GIJ|g;!2|2tRX@#`i*+?hYDfPo=oCoZ*Sy z+rRS43AzXIDszf7W1Os&IvgxnjFppSF`Dw^kQ>EL#=Bxmohje@x?#*jO7~sEeqz{q z!(KCNlVRNv;mXVLMYZF0!|pU}t6e$4^c^JQ+h9TZGKdL6f$kJ^&eE$2Cu149%bs-8 zPsacM;93c`I+(O8{osh|E@@8#>L=}g?X?ng4)T;81IP)+JiL#F&L|uMog+jT#%N{N zejn)N?wz&EU_6@iY0_l{ik;xT=E><#ig8(i(k*kQd^xj4u}ciQ!svcz*pCf+!my_d zd&e;LtW;iKq*1kZCuhp@9y07P!?y5R3Ff^ZW1I=G`=^!fY)9teLEw7tX3ZE0%J%dO z@*jJ31Zy!SdnBJs$|d`9dp%nhjfF*oB5&ZP>Mj z-D}v-413nF=MDSNu)iC&3h7PV!l4Fr-+yBV4`J=K-NCyTRqz36IV;@3`zxbTRJh8K z*&)CAgt+sU;OPmpT!N=5r2R_=g%@_DP`~?E_NjgGD+m8~SbWiXgw58wbZ{dA{(U@K z(#zA6M6ZOqw2=7^I4qv&C)~-Kf)a=6aXR$L&<}?WGq1ytPTo<_&&K;P(9eN>EOeGo zD9Kz2MN^(vZP+Yl%JUixYcZ_VFiKNi<|&o8+OV4qyWOx~8paA)d0AE|?;i~N#IVl{ z>xO)%bUmC&*ZnBQbw4VPC;2M2zhNgCHq)>s!%j1dGtJ7&K9|blQ8tRP0jt<=4SUA0 zmkoQ}uqRReDDTtG6zb#+hu4Bez-ll}Oe?Cwojj&wRauLw46Okzvcf&R>_yUl=z;Jb z!Q&n2>1mc_Xoa&Z>u7!7$_K(TP7t@&(HoEKMGQR~$!4W6YeRshJULBJv3Yn`j2TI> z<%WIFu_9w&MHjGQ;R34YesU7UzDR#GETkk-4Ch{OH)2{S|brXd`4}|9m zOI5M7oYvh-Prv^k9{SEUNJqMRn!ZtrTl(hp2Gw}icCS0%K70%LmK^%dcnbIS<|19Q zw};f*%4nPqoxQy#=*(nj)XFkbzO$Oy1COSEnsj-oV%6@e9t5x062q7i6g%Ir>kYff zum=r$)Ue+f_ItxPZm9A;HjInI73=Rzc^>xM^|F1dNot0Wg`h1%9gFc^LcrXnCmzMT}?2)<8_dZxC##an~s&Gm_ z2`QK<9b?{-(yO5}rPo1cN}maRw0mbtM;Fkgbei(KS%%GVCOzz3=~(6~-72HI)UewO zyTh=@4f~B@FBtYm!~S8|=Z3MPr}kdyOnF}Tlw8zSrr3?uQ(o2774HWK7Up1i?kk3Z za;S+M;{|K$EZmVofuG2^x?==oUQiQd9U@rAWsNmiYN9MA7I&sFB9KZub86lPn)*ad zl{TC&fBBnNMA18JClyd;IX}DRKZK1*q!kamh1PV3&`u z&ZOefX{Fg;0rc&Cgn3GpkDTJ(F>~j*&UQ#oLpc0J6)XV1PXP?B_*^eK#53f>7{XSu zDxZsUgi&Nv1PL$hW)6>@f63U1A`GV}!W0!nm{y|*!@F~2F*QRsIMt7*OKO@2>`iel z6q?9l>g|L}(lAUsT{7URb6i3bv1@zbqVK3^m!==SEpc2z6S1ogz6J}@dAel4^)1IG zG!eU4e+CQEdAg*QEwt-Lj!S4FcJ+(c#Sta86YYDDEpAuvDb5!4cbqrvdt5*yD&zdo&vAD1lSNuwMw}+T(O_8F z$g)u*v5MBI_RjYjJ9hMFCFMSY64_@k3HfoR%Nd#W8QjS_KddtBGnj_L=hZa2a-Q3j zVV}VWwxU8x=+e&jqNv+Icc-Ie*_LTv0K2$91I;(sqJm=em1*5QijAIZ@{U4@dOS;2sBH2|@nIHdE@cY~iq>b6$IjZvj)rtpnf$vB_&-7S zeL4(^m2)pX zgXwQ9=w41BuN&JhA(c&D0qE{>wAtLp`1m7eUUPKW{5u98{sNla*ye$1E5Ciy(I{nR z|1$hmfo>#QI#Ai%$MBosXoL_ynfyz6GeOsxZ6GL<7rNwyIGr}s(eRzBys*3+W%n1^ zFY!IF&-${@wcGNo60(w+B}@;mYtcaH&Gl#0Rke8D2QV|mG1?1LzpB0UkhRzRvFC;l zNBnl)cfYgR^Zp8a8Xlh4w$=6%46Ti{w0F`)xA=qyM zDoq=LWp44+tF9#W!VABVFZ`7NI-8$)T1}@c4yC1{I)!e|bZb&{&9nbGn33aHWku2S z5NqVFSsqp~7+gKQ2}M&uM6;?C1|H!yxLQ_K`=?s?grz2Q z0!ncD%WasxnC3#uZHnaG7wbE&%Oyb9D1Zgva-pNFzzKY#gHoWv*I;4| zt*usKwa|w^KLL+UEYOt4d2fdu?M!)cNte>q}4XjSc9 zjnGs();d#Yj&};kf@F6z2*$LL>|RE&sS3}F)y!_GYg#b>-;w-+q&XJ@6WLRrpQzq| z2fp+~#dOHTqG_ljNeD@#mEn7YOF}2YtVxI_cmltQVeH>siF%r0XBc*wVc#Fx~}l9V%?o7{lZ7~{L53+)0TC2g6z793)s~0l+s$mfaK9YM%;Us4+l3=*$F6WfF+@#Gx$2UxQovQ0?*nMBvOLHI-*^{ntP(ZY zXwvMV7_*0Bi=0WbhhiHHd(r5kiH2oadLiXUD3jxh8AH`>Gif_Ov~`du!IU~5mqDk! z!=2Aj);pimq=zUeM*k{yH}X)B4HzQ(rq$A6A3c}RN1+>C68MR62p603<%hEX#%^0l zu&eV?vGWmXG3O(i)JKZZM~Yb%m;@-u0vDn@OW%UQ!1C2=8NJ3aHQ3`fe$&_FuukwB zpXtk7!;N3JFeSY@@mc?sjo&}RpKZqy8yP`X)O8089IdN#-2qe0Ks-}Zw&teTND?=G z-v>*3+4&Tg6y~}lFatcAooUi76pFDWs#vo#<$I?acClfX8+NNlL<+krQkk-qtI3Ea-K3ycE#4J7)0uQnr(#zb_8p`9v0?Wb_6NgWF^sKVO3C+H zoC)izR!T~EkfmP@o*>nbGJPc>vn3TrxnIhdY8spB=hwH?;{>?2GkMVYEES3R$`Uv`+F!lEP(w7wiYP;64g+G`MNf{RN86!n71ptEk}QS7M6%RWU>X`U zX+fbF3kt=eS*krBJ)hA>9qWoE$xbECM}wS?c5^;D&U{3Z`baVQNU_?5O{dijA2q6M z?4stHdCfJ$OZ`jWzQh~jgUkVUhzd`rvQ$sDI*!Q(sV&Q@Hh#@XaVpi1hg^?Xcoi8F zU{0!SIjl``Qk+8Nv=vph)p2dh=?2c6R4L@-iInWCVgu zgu|yeCTBnbIRj&I28bNMmg7(X%hZRS5W+73!fH^JPqW+yjEik?RX)w@K43JxQaK z!jX-Ri!|GKJmV#_Vy%tZFcDSc+}W88i^7)~r&X`G%Q)2bOeWnQ=}bm#(+tVT{Yk83 z)Ut{z0}Fkn?X{4c?3X>K^)Es^q0zb!YNL`NEa*#yz-*zLAqf3&iaFc=5KbXM>n&s% zVmcEZ=93Y+5KD%jiv;O`2UZN zTQUc&y;XB#_8zW>^UCSGJIboL?xp3+~J`y7DZm=3Zs% zDx`!iZPgsd$*Rz{c*?aeSe;~Ah4N_%1vFb(Y#~9Ro0)Z$)}4+<2=S9i-tEBe1>Gs= zg;UW>nO1#O0>2nE&pSFcU^B_%aLUJ^ndjO8tnM<&qyL@+%`=V;Y#HTE#)m(GW>42X z$tI80=7oM624<>E?xTM%1Kk9+#GtbIm-fsD&FPLVoBK9`ZYgML7!go(M<)Lg|F)wc z9aSdx-3fdR=#F6v4=S7c7=CAg<{U?t&3%>lZ~r1@qRk4F>k{6UGY8?`NUNZp{w4j znpae@3Ytf*9AnqGSN5L%+T-VgJpaFshw#nz1(if%4s zR`6BlU!VId(VOH=)Vlegv_q|qa2w_xoZ z<7!4E<;{pkAC}~8aTvspr+p7W%Nmone?Eph&EhiCDnAZwec7x0%8xkun98M_SwdE> zVEO4)j`)AQZfOt1Vh>K~UVqtuDoiwYInwL~T)P`G4Oz_ucpA&6~-f(E97YH+ggK z`|i2t?)!Q7u8A*OQnC`rgyhzE^3{0qgNhX~*i1-18*i;DiESiVRdTJo#FNjcbv0YxWAWt6k+Q?ZG#{qa6l#7HAf!#q7gtD=~nn#F{^TIj3st}2Fp&1J5VM4tHKp~8zz z3xraosi6#63~#$ah=~2o?-19Ocvj)z+BH)*M45wFnVXX%5iFP#7jK4{2{1Xr1mMc{ zRwCdtIf6*;3c$hai;*PYo(0wgm=c{SG%?sSfRiH{K%c-t+!qk$PbnUbC77F3N1$6| z0#AT`D0DPj37DNK=qExy8ane66+l*ihrp~Wz%=QJkBXg+cg5(BVrN@yxy8O`u{Mj{ zY_XLVTVt_x7JI>B?^$fK#qL4cslO|XDY(Ag0NU|cwyl0s1Oic+OKnZ=OYNa+?WN$) zQd6QHA=jM*jqp0bT3>8Z`Vg2krD@WS?iE{tcg4z&!=VmM{??+hq?YYO>+z;-C>&H- z5*xO%a8OlAX<>0*Ve!PGc(MvaZey@`P1DrXoDgU`z{RM8@#M?L@~L&cFH$v_dMsZY z^0CEW`B#-C^=389!(BA2o_!Hhh#E^g=zL@KW*o3y8hCch`1qZ*Z> zd~5x5MV20h73*b_8@yEA)XQ3+te32G378o?w?eV5UJT5utK4IX0im~2drMJKCl^bO zmjibd)29>EZHoV2xZS@|4B_)atP#V zM^p^A35TuQhI?(cC&c*(0+fBvka^k#VGiagV`3Uo1YkE%F<-Q~HJ*CA>w`4X^2_vK zwxS`1*Qy31+i2R~WFNCzvyY~za|V7Dn`cZ>hlNV9OD%T0#qP3L3Gzhg1{qVZX`2Ju zcp%r<&{HwA59E?-h;y#3+ZOO-3b=}X@!j9FpM;U98_HCGQIK-o)E zSaZd}A!DM=l^Gm*t(6WA*;p|f+H0zYnruMAO7gSU(d4H|Z%S3H3Ga$6Go}KEJ&j^) zs+5jRm0~gEhhl8B6e~aOBn(snHxQS{lb?9=6rI=#*MgVD z789B=pA=rXa@(T?t2vY@_YGyH)J$E?N_H%se2SdPcrc%0wCr_(Rp7TwOm+B89p5ZL zc!MR0l@869%xSL5r6et^Z*G`%4${z_Ps|Q9E4}2MbCF))OOc(liH%pP!Y49bsp{|Z zC^&KHk0Iq)j8o_dX1=^l)DDf@sSBrR_u%;z9+t@|Bu-amh*S<64w2Z}HNmW9akflc z7TI@GHWL7}C-o*Stjy}@OdPqQBPa$CvZp41ZV6@{xr%vEiYFh>fd)JgC70=UGIaVf z6*>cdDs<8?$F)S$q|K;eHG6}xWABN}i!`?taqsgDng~De8e%*9zPw?f9PaDxJ2l=oS%ZuEDU)Bt&OoA`j z(`PrhL|*vPCzId{>k@fQx_Ie#)5FtK_^bn;U0|Y8!55m`5IRmwhI-Up<4R~!{8B+B_7wE1=8-Y^-T_!=8dpM-;@93Oeoc90(WjoPD~v0l0Uh>k z4MKB@s7GMAw#I)eaL~?-p2HV8WFG<;IC?3J zAoU=lbP6}6Qx7xBLf0-sO|*9TDOu?GNW;y=%GhjeU(#bp>7heL2&H!q^EojLomn-Y z!X!O%xrez7%}cKLFdxUp&8NyK5fUQl@eJq==a2!4eN>nv0Cy5vKr@F!0w|7iGD#N1 z*bMqq7{5DVzaQwHGqh~0!}zh+`V=$^ID~*=zaPf04dMGaXpZ3!0g7zH_)S3z^%!XS znSmPFhVe@vohkXypG`e!@PzSWcxJF+_o*;`9Q!nYt{0ngs7&$Y_@@Fi6Ac~P>M(xm zfu8`HA#CWO7>-Qgn`>x<5I(4F#DpUB_e@q0;R7003d{bai51I$rIY2R9 zVd0wtykBp}X~jd8sr+$l^gGaecORwWI7#@0NP6szsroQZ*P$4`Op+d71I+|O$6h;= zq{r!?@!w;ei68H=zN{U7jONck^Ms+x7QPoj^F}-TSjD#)8W=@o3SZ}#5`w^c=pKs`;NYA%%j&Gu}}BH3sKwNj>yKfz5(G0s86CPlVn8oq2f%^aG&}!K16SH0f8Cip?~( zdW(}{Y+#kH)tCyL%Pe-C#cr_JgBDw5v8OEdti|58*!vc{8wsoa-eXMIdM$^w-E2eb z(yqc_YEW@>^jLc(b~{8$nEFg@SJ5B7vo|j>AVyjV8Zl^2(0_O@seA~`n#wdq<@_MU z5_nfEzHC~_p4_ZSmn!)*o_xgq8Iv7vB6sUv5M2SkpPJwB(U?@hiNbWTrqmf0yTS+(};dr_h z59^Yu42_4Gs)tD~Py$8AZ6{(R;g?nG8`9)>dpNy?nj1bkVm=M;V~bT@rGbL1s5&aJ zvOD&h*-t!&P(F)?`cgdHnQ3wZo~oPLUkfyM;T7&L#^6GQS2PTsoI^EiT*b62#lvOp zN&{m3Ji&B8MNSNceiHO@=%~<%$3;z1Ma!|U!{q$3ccxCJ1M+yC~KO~=zFWpwS z>b)tHrMcZ`pDdj82Gz6p53;td<($*1E7JUVMu zVc#WiiqkC%8!LOjL4GkzRrz9?Rk-QV4+}4>>Jby$Qn4wuXlZ=$L$L{C)-|t=k9leS zfH-}uNoj_&NQ=N&FaDE_UP}CWGgiH9{Cc@D=`Hc=9f)6V z#BX&hKIT=%@AdinN&MmmYz9jdP)Xmayw&k-s}D!~I#rZ9plaUekDxzd2{&RI&vJR4 z^jFPAG**)a+TG=g*0A(coCdksQ&;Z}qqbGUVPfgdmrXittB%IIwpBIOwi%|eLN^kn zQ|S(eN!^|RliKdx!L{8VCT-`+tmz1tz9wAq@%sTDE(8a!Rp*jPKiG|h&QXM_Of6mx zqFVb)6UKud_ZMD+J9zheV(n6Fy#{ZfymJp~pir-lu(_;?L>vmPVn@Y_c6D{&+7<0$ z3t1u#N;}X2>$9p7EMAR+XqEy~1^fg|-B$EW+lscqj$7~jp?ASBgM8R-w~5nV*?_Ku zJ#YIWUv3Feoh!db2*w3|Dz--`~!I~jP&=K3t-Ndd(irrO_J@MW2m`Hc& z7cP(-XsVlO+xh*`&UXcuXJF&D^RC&|+3ve-|7P(q?Z>qJ8(`tK{V@bFDC9rVDI^G!pB+LQ0PPSoIVtlP1IFOv7&io8x(E(HOk`8>=U0_O)7yTxL+ zTkKwo-Dk1iTkKVf{l#MMSnN}a{mWtpBaRxDp~i%|VllQx8a}QGC>^W3VzVrEhQ-dc z*f%V8mBl!bQ@07Enetm=OhM_z281yvTHFa36^F2oqY$df)QX{O=Ps(2ldM_~|Ct6pJ>+ zq)$JSE~8+l=|WSKH_VB=VgaXnMso2Ui>*|uqnY0{FQ*b=-ehN+YeDKYn1yk^j9=CJnu z`7p5u?~3RL%L5}xd+yzE4M0_uj+!e7?Sy=X0 zOjdvCaKi^37u>TmVG8>DAxbZ@2he`VNQjjK&~C_+UIfIlM_N}g`sBy-V5>`Y6mo#? zm=z|vLZ1YkX@!xOw9M!^OwQ00l@h4fT)ZpxEn_NhF0t5;Ep~^+V#ptL8x&|<lj^h*%{(Z@<1f*TjtVq3L#IbA(5FCO2%V*V zC?0KVXwueIF}ALXEwFUwSnP6(U1hOfSnO98d)i{pS!{a+8Zpk2b~9C=5u+)fjH{Zu zz;uLQBGC9JPoS|DXg53_AEuP6%3)AGY9gO1!Fu)U?CciV$LYMGV^e-@UTKGFz)&0T zpcnV?<7m}YtU1b0P2_j1U~)_5;Yx?1WECNGp(eUu9_2Z`dgVLO;k!D~=Q=f!ycSPt zOgQ>;)i@ZGkDADbD<(Trtde2~scPqmRZ{d|SL2xqRr!S&*u&;U_)9hQl+JhRgu*X2 z*cmo?5m-pMAzdc1N~SA${rHknRCjosB7VreAurMfn7KifNvx73qdV-sTkzhdbUy4` z@*)YOVGJg!uYy?RdW6GG$1fvRc{lj5eo|!;t7JW3>UKQx7bm8t&u*~Ei%^7sBSotA z#43;bycyF(a`fkWPrT=8g2I*mGRvDzoB5xYR6RX^25KpYq6}0rkDmg!;^292cYO37uG^8Qtq#+ll zA)I-o^0_qy!T0*}>(Q-vG&zc14&(L*74tS#Jd?FN6=7SJyLhH63c5R7;SNfEg;NJ3 z6eMp@5?E{5aHWc8{?WusXi`Kb_Y_xb^GWj9fk*WA$`6ITse~rQFYXR_ex-_M?yE&D zD7OF_gx-oTYL)%Bdw!9 z@Lc`NxDp!BInKV!RHHgL!|`ThAN>b=_@yrWc&fOi-zJ-!WmY-U8oPWDE(GcZFCd!Y z3O$B9(!)b^RU!k0KZ-%#snHDDW{oOh!vzB4sgWlgIXsIzDbMEGIpU?+WlNosta6}k z0%w&1wM5xjNm^%Tq$Jtdm~6?;$R*0oDhCNyvmco*-pZ5AMvO9NlR<{7-IL5H-&#sS zImxWAoMiT`m~LaRCVo-*);KC}uJWxj*gN=CCi&LaL3b?2Zctn>36p>1Aae<5&ga++ zid|8dydnokrS9mDgivAp?gTy(bbm6m9Bzd1YX%<0Nb!7*7NN*Lj9(kVw*oX%3WZDt zprQQGIIaWD;bz3l=!Eg(;PY}4pN^4&9&?cp*Ua_ej)O$gV6Jpv-g8y_%g|R z9tD~c4IO*PO!BQQpt(2)ewTyhNA2)qG#>!X%Q^7-6KMX{4nJ1$ZZZ7$RHpd$h#~Ls zP-Tnn*cjRaJXG1zZ(0oH01uVR4-MW|SiTh>U+ft9)?XvaJj*OvY{ydmAp^fcagSQj z3pU-8)+qG4i|5E4PNh2N2k!1sY}+ja8#q0U?zvLMqu+)N#Sv^@@-($G-tYF_M=w3x z{pZ*3`DXINmxupP-qoI_hD=P6cV%hYDd(uA%DeJzEjHI-@~&8+|98o|vZ?T|&@U<3 z49~yhNor)_lL?_8?n!EOu-ftRu6MJ86BV{dj~vCw!ac&|D}Rg{TPMusLyu9r3laS( zo}b~7jXNZ5h%&49n_=b3yT(8n!+66xM$MCXFzffFAn7ko-0dxFNYNQQgBXNtTE$?` z0J^6>c_MLf*tlvw45fHDzB$Z*(=k-p4`yt6{&&i|#t=EXMLP>GK_N?~1{Ft3w=s0nT#sw>YYuJoL16={oiU8 zbFG8pd}jcD4;Is*_&rEW<1KbPOrr&xfnSKKzy%xC5AbjiF_;6KmvC5p3LaJ=Rhe=? zr=HyO?Sc~TKZeZ{bDe}S?H3nwJpr!W<43~9Tz`R3-iwF2E9zA320T?amA)LPE9z7W zGsEuIR>~{Q2Ie&cu9&NyFp^Eom1$RshuaR7c&Ls;UFJ|1tKC-2mANnl?-QUSon?b= z8g!=lsn8FE&LwEwsH5pWBIddr9{Y>4U(9v!*78g;uAN=k&v@&C&cBO+i3L`SG-}u% z;>*Ubg?Q_-@z3CS3D4_z{)%T4o`2xkCZey`GYk}cZL*@T<9ST!*B-HwuP2J+>-e>v z;HzKkwI`@m?6sqqT(QueYbo~H^Cb$5c6`aAFQtgRmc(1fuXUwf%TaA7txc19ea97H zKVhvK&k3zZo0`31no)?*T0Ge!dy^a4`Bo721dXhfgFRUq3-HP$2HS_R6fszduN8ys zBk}DMh;JXn*Cz%GF<-DgU~^&L1cCxFSj0X}3Kn9%<*eim%YD9V?`kVH5%1cvp>`PCO0-#OOF>U{F%oMZidDiiTDTl* zO|>wkwtHd1uFat82bbKy;}Aksrgl$O_`;e!?-QY*uVOXQ8)+Ph{~XY23w0Lvv5 zX+Ne1NWjAF0an5s>;WDHX2x_z*p;EwksnsYU18T+fZ8pj3cITKMn+**mbFs2?1Sec zvVg)arWJOj9m;cJ1ay@D#5m}OK<6eT>=Nix9Ml)-H-NekAlV=yB+%H3^P*mWI}(axmK#7j0|*PpbTI{$6L zu3P|6m8tBTt+niZ_zn_wWq*~Mu&cix`tKBW{r8>TS%(6!3zBsUbeP-ym4!FJvmqLfKURbNinby%Y3JG%4e7gpprDKA1fgk6ni?FqYv zpS8(Vr`&{HnXX)E{l?UHo=*=C1txM6c4f(+oWb2cTzX_WAKLui7IvL@LF9t;c(FOn zi`8;uVFb{UFXlv@p zqdQl$^@^eU?CS}s<|^8{=G*U_ESy(A=O+(Ti?HG!QVVrUqG~#k`;cr zPrt-Ps?4X~CZoJ3*=3Y5rKMdg2$4bM_Hj7u3RPyX_02moQ23)5ltf95X3#ckR6|8u zvmTYYlSEsYbeV-f#Wu6_C-cQjH?s1uMA=!X+^R^=mt@P1EW)-7kt?;Dm61!7Jw)w^ zw$eMLNf&K}Wb3FQ+acLHd`PJZwu)qHkw~_7#ekGE392y3*6;bo#zGWwM=y_&SskDg ziB&yE{&;bRpY!qT;SMPb7$(`u@!}PryV}r#eW>K)G+5jSnt#y&6vx(Kl8PJ&E_65E zNeC4tN!bSce9-mgKog4IXX00BXoL_yVf=0eeiZ2b)($^PSniH#LyS`gs7&!)2fO`2 zgM+F?F-l?KqxDD(a>sI@3zdlt zI_2aywl&>)M(mOmzZ-no&mYFwM!=87!_z0f?Cqic2+aV?5Ad+K@LtcWFf`RrXB>%3(0+Jvoe=t}fyS)iFAQ2NcM%hcgV)M37%Meb^|w^P#;QCqc`-p|iyw zfJfJkXo@-~SnOnDigMk_&|$?%Oi|}@i(O^0pIYn}78{OyQ$Hv_rhcr5!P>6sPsPiq zK+d|&bVt~IH#BE+7mC^f9;J9(TY6$R#sw!CP!k_-^PfhDAy8YzqddRZ&FO; z8l)aFtyrSGdiXuOl?CEwIt1)_}U#0k~WC2bweioumccP43c! zBRlY`7;{mv+bnjc#p11usk53T=m0!k>eS$EOdxf-0Hf-R=d$qBX=-km+tAXmu)dwf z!q#$s?z{XM8n-;}W@6d{I{oE7C2KqFwLH_Lxv$tFW9z%;vL7HXYWt%41~Xog0aR31 zgh#F2U4nl@E6kh7vezp%r%Xp}PW4a=#z)_cP%L|ARuKQ)!ZAyf=@vsbjr;`>DVu;p zHXxEM`@yW)LX#Fm#aIv(JKLBFobxR9eT)6jV!yN)zj08vYE!Yws*adYU3ujA z@|5s@y`-X|+`;-m+3+&Vx{Mk!qIB4>LrX`E7~vwSW7z;wt@v_w=%|sy1>(&wePsQh z3Z3OtlW<|{2iLl_z|c4$>j#_BfjtqR%d~#*8@JOl{KD1`SYbx79{N<+{CoxMzXrOG z4K0HZHlMy0cpuc(`^?ZHg7+|f)rbeL)!faLuaXS>-U5Ce>QgOC8WbyD7{B%4$Jxz1 zbmmlp@Pvi$3gG`jM}OJwq|yQ%#;*zdZUIeCOa-W7c*6K`M0LX6khn3!r%d6CA;Hc8 z%@4>3YJWUo{FonKLyzZIVc~lK1mi%r&Cq7b4`#!_{+Jcwp~{pW8(}vFH2s+oPz*<= z@YNU^A;eFn@YRE^-vFh`6h0)gGr`cb$FB->UG@v`3w#;NVp3{oTz;9p6fFl`m7!%g z!oG|pzcX^=cP{9@)egTH_}vVeHHMD)ktuvngXYy7_-zHvo*alnW#hLmXbv`XZhX;1 zeUUF&*=scIoOPtS`ns7li)PHO!~f9Irp7tv3>j8B;>#~7$@zc+-B{uKC`@H#yGr zf**AGVGsUk;)*SM{HyCN|9E-XU=@fdicGEDbkw2&$F-E5_vhL}<{gApz0;BZMUg+g zd&NVyU0c|D?C+oY`1y05MicQ{!7pEW+}8VhUAnyVS2Z^jocXoqbiGUtP{w*$Q*-0# z&2@8Qvl`~q&yNjSR5o((w6hyp>!y#=uOc$pknH0T73 zik)s7sYThP&CrIVrlG!NR!v>b=lX^%jK$#(8&J0&yv%VD^!jq>3=0MsGGi@;S!b*? zMV*WBtJtN+6m@txMwj@qmXadgkby4-uPsTya`B_vCM92)klf5~1{Z%;)I2$!TvE~o zo2u61HpiFYYr;u+&l0;@u!(||O-kba@+Bq9f#I$Jl9lqE9`j{T)iPXvz7cN@KB#Ib z9QItib>ilwE8~UZACE69jN^;K+IX_1WVU`*$YrnLc)azEk2*L`bs!fwmEYSuOIgi@^cZL@x_zzK1lfqA&(qQz~r5!TQ}1Zvb?B@U{F?B z%&erGvieasQ@=h@re!WEd?zi7fka*6GOuaDbj!9pK*~}i*&w9+c3D}*19WY8=XL>$ z24pR9_8T(@JrBO(q539bdL%gM!M;BPH?ApFi(T3e4)*1mQY|cE$j-@;xpI{JY`pi^ zcgXR2_EfT^Vy0#lC6jzGbmnE%pEazx7e!|`-{ciu~-KbM|IoDn4-?E7Teuo zT-#K-{VY~tvGEq;y%S2ubMk45Iy}o=v2R-J4vXu*d2 z4nH?itV^Ct*Ugx4SIcoH;I5YAD^9F930Ji&M_A%Xw$M0kVNHD5l9B|CXmY#24}O|> zj~wSPDfvb``9R55SWZfAtwIA@1pBJwmU!}QHlt{zpNBSO{IJJ(7IW=J5Q5FPqDjdo zX@C4AT=mk5!<#2)8(bbwKE?NHT9&avcEFD>rSWCwmkeU_udVX^F>)f$&~-r>@3yR#xTnc^8(*N#{Fv!ZZp`zVje{M~mqh{Ialm z&G`Z()X9P7{4G$hV_S`f^;gw)H0L!l>sv5*ub-(63aSX&X=x|DcKuj+KN_iUtnj}q ztcmto^vObgBFHBT`FE8yLgzNoUh`ckv?qbKQfRLh*8O4jHOXF!eyEUh{q;~Gzg2fb zg*6s`#g=`=NU^=sHjIPhoj=;vZiXqP0eAbL3L$K>4ol^oKkAUBEY}7dPJ#_OyXgOSr#*r#mKEmC*II?&1M=EcvMoK3(>*{Na-q&aK@F_RWKC;T?G?JAwBV<8hn@>lOviOFkB5FH^b?>rLI;+(8#;EM6RV(4h0gkVDs&cv;dr!bp(!ex zA&OmSY@<%n(tX!rcUX)Qe06)j#klCJ7`qnb$F4;&b}fprYf-Et(nhha#uRmWTCA7F zhFNTs#g4QX+X3Y_$6`$uOIU1)#qPA&-4=V^VlP?juNHgPVg=|>G|Yv@6m@uUi(>3} zG%VvSHo;<-=DBpsjVX$5WBr6>Q@c!9HeW~h!?sPpop;GC6Bd86>Fh>!25m^Mqgs1( zov>`&=1Iv%30)0n{IHckHu7~jUSZxq^Tld@ndXF=*TI8FS;#S}|9eZp(v=JHA0X!k;%RR{-;s`?iXbmP60ZFN{274( zzRhhjzz2KI0@$uE0t;=lCHL5jCID$uYew@-U8V7wXeOf)Nq>;z0AHHp*>LJAmi0Iu zE}%~{;4n0=2q7DQ1PdYtSPAalVR)5bYGH7dXomhZ=p4h3g?=vda_F1^jDy|^9XT(} z^bnY}nWjl+0E*GIV&6BW0_TSo;|xIQI0I0+wHABAVr+<&?r#?Rm&G{lSGOuQ#<29a z7#m%6%jv4pEwmVKX;SP4i``N&OFTjkq)kPN?-=pnMe88q8-3OhfD2s3|>PY9PHnc(kXDH>b35{k^VjD9Ypxr z3^OooXz$Gl?z1g=shf;wQ@Q@a5|^o?KpS9`(!z>%4*i=^t;a%37a@VEthNU^s zaiq=)uCq?rqN!3}Svzu>6;!*~`h*j;{+nE~^T-3}Ai^hE5;*%LC|6xyE20_&=m1G@Xe zob*o>_HuNp&=)$V3Nh%MD(nmWLFlOKiKn6O2Yns%fzUbfL!V~)AewZlpctnLigBu- z7^ez~-EOhFEXLMI>FA@yn7*kv6ScsLbn=wTlrj}y8EjGqtU$~y*p`BK@FBntsPQwM@cT8Zx2JNG$j`+Q<$h_dvOD?T9)`agx=`M&Bt;sI;=bNyW zy6mCTUzS1y)$W9#%p~y2AK3}H$ds~!fayqwrl{-{D7GB$ib<#VHeQ7@S7W>$jN_c( z?hi+1RE+lx+Z*qlD`zXC$w3l2{b5*{R>*3MpH*RGm!RotlSU(8)-<9i>YRmN#hB}g zt+d!0i>=rbMk^@Jk>jyhO3074E2X%Ek@HrW#Jar_ved--ThN(v-!`#71ZIsrODd-YW%*6n1h7;j$1e3okDam)F9^RbPi8 zcml*xg7qrtibeljor29>H*{VpSDsaOC{=d}Xe?u6@Ms#dLvmF)48c<%ss-CVo^QDf zp;uU*YGMpe6l~|6@37e|KJZ7?7ZbsCo8#qI_V^xG4EU{J{qzN=mmEi~Eb@7g75L5P zD^w;CT;>~H&l%VMiF7{f`tu^y2y+QcRGCC@nXdHprao`2O6SuRHhB?B&kcf!Dw7EA z6|iGT{?oln|B}w905*A%Ch&>DM3qSdmt}|HDS!IS^V9ishfQ82hQ!$)CaO##xNbU! zixwBcWnSa~{JQC!=`u4m%}nQT(c)s^vk||pf0@pAaP5!z9jH+&WV{?mf$vj|A`Qz>)rb^>f7Z*9zxbiL-yTl-#An`p0iCR~$ z8^jY)jxrIUx>=gB2I*pvW`h)2z_%7c01+^wTyTdm1La#lDM980| zVb@<4-r%{q!nhKeluNeQM(0Ibzh*an=bPFl0CpZWu7oD#lC56i%Ju8FHypCabG6mD z5}FjhFx_B1#V@n#_n-acQ>~|XarQSwSZGrG+8efByhiPI^n;$OS;m#nr1;faT*dI~ z`sJOKaD#CrG%0@dN%5=W0i{oPu3j^)ga&lz-`r*b<_^yOc-x-wa}Kmzj7$}7uMd-R z)PcD-?8$@l+8}4$a=y3lSmNw_(`Owhtol59@AN~+yFVe_CluwmA<>mfQs%XVt@xlOI*!KV& zK`aH`p{9Fca~t-3!L`7-0{FS1V~ZcguL>=AXAI7c>j46&5nJRW^xT^ zqUA~#gBF&4KS217s&Je)4_7)C!?5si3bS||p19Iw%a4IaDUJIZ#*g`N5a`}Aw3+fF z3cBtSAy0~jDpP)Jgk3+-bgdFHsi$G_WqBEIXp}NMz7N21BIr6#QmRbhLoz#u7@GF@ z4F%ob+Tq9W?S8b&N%gSwWBbw@bn6UlrtmTSwt}X^WaX79{r(K=ZlKw0=opSn>33kY z@^XJOg>NY6{$gk|g^%gC%P}q|)id!c2HnGk*76Ja9_sx7zf9j7eGa;=$Eu$UN2c$g z1{xYSl$rRA0^PWF_{G4a4m1}TI_5_veo4@Lza4%haDOjoUde&qo1od$4nNla?#JQB zr!s}F59kIP+HC1}WRCn!0^N*u_{9*ei$HUOq05$jKLO3J+u_Ibdl59B_P zg@}Cb2m7q|9X6qnSy)#yr(u2z#$R2EPXf~#e3w%4Em+zu*= zq<{a$6B>#lmwa~RlF#nB_sW%Tju`s4XWx7emsAOU&}j|Veem0tuYdB%XSzSLW_dN5 ze8Ee`{h`o%)?E->BZN^DYak-`VZ#9&I=(P4M*Z z=>E>|;GsGVhLzCE@qCEq6S&!dpJM&*i@e6U_0#4y%xG?$HotksGBC5Tvfm^Z88bPegw_yiF}{{uW-@bG-J@1Slx z2{VUV1tMcaQ&grIVc!#?D(>iZ-L=wf%Hm|TytfQOHE3$r|$HB z?W@8WC&1@)q<((BFlA0rXAK zSwFTwXUi}hkG2dnMdb=M#hQ$5RF(l1OIYj%V=8cNvDnWocCW?OS?mRiZLkWd< z#?L_1?LRE`nZ^2aaOwIP6Z$MP$Lf}H$m*6~Z5QdMg(sMg3){dX_2a_jK&p~AmvFao zLh|jZOPHqiOGrd}Bi}Dt!^D>_B2SfXB3E|R-U7Ve1{(`DMo4IX2BX^Izvns z!E~0G^6|@I$S4?&3-ol10c-aH=xpFr<ZTU09xkcZwC^qcmaJA12?2mi)wXxLBVlmson@*uzy898tyR zp+***Le)nK^+}LL3YW%ay-DfQ7%_@TA1e+gT8E|b&L8dLSj&Ra*sh%PRYKcl<)q63 zZdtoRM68d8w?l;VOzUlVz$t6Lmxy`_?g?qpH-L-`R|Nc* zpEJ^h!1d0|>6oCOSt@zSd}9pWRR@%9X2;J4p(o(|1;&XYO$%D;XVx%7Xw90ut23#X zo=|bl+pSAteFx|0;t>2!;v@0BP&d#n0qxm%D9rt>z_ZBU=NtVj=ZBy~2AE^$Cf(14SXTAjeg?Xk5E#3kfo{b+i>L21P!=X7VT>v4%~GO>`NoJ@ zudcjrjF_iN#GQHx53@@lmFzBsN6Z}eD(T(8n|YwOftrk=lsI#MnF2y)N-sc6b!G?x z>dz2+u<1Hq619Q07Vq5OT4V5^VkE%Y@N4L7gH}L4ANqaJzXSa@(0>g5LFjive*pSD z=KT@qEAjq&=np|(4}BGM_UnA-3JCm3bb-GQL*E1XqtFLJe+)W%?#H2*Lw^E#CG@AE zv&cUK{S@fWLZ1))dFX8KFpiLs%S`arkqb>xX90c{JI9!!&Qgmlv)IiRyUk(}MAu*D9w*w-v}n#HDDjABp9k6%zJziTY^Ba87I z1f~0h#a^@+Pef3+Z(Hnri*-l&Q@8wBPw6;@QEY(4c-4wx6D?Mi?_$-)^p*W=bp|p? zKU?JjwKsWuACU=894KeJ8|cWA4KBt(Y!I3H?A~`3XnQ_btwEmu_kOUdlgHVTD*D6n zUW+G+XBr-=N;Iu3`s1PR2^|S8pR8gbUOri^hRy-&G0+!6N4FuLtR4@YlgpE!w?dx) zos-KtJlaIlq?1d4A0AeREC zk1<7^@fPD}-n7M8^cLd>L5ls*V%J-2wZ-^BP@TAa$6|l8SU0pYv@LKrE>OB7U|J*? zw-ad6Nu$zn(x`OqC#&v^@#+ZjBlS2MLELE~=7#r_3}KyThnGw)nc@-gW@KW=85m)u`GS*09+Si2QdROPPBHmGE04Ev=V%j>&j@?k zajF`eQ)ZfjPDsAs3oV)pU*LzWoV4`)mM#<4j+b_v^S=ZMypwR4guZ#-)YTjY>BR3e zm>TfpJ1m*A#Pm)4>O}1tm~`TIzcsx96NgLrGD%b0VtAmYePEg`wg|Q*H$-ST&m1Cw+21!Qln*N18P_9X?R}X# zNK*yB+GDV&g--L(qCxex^QKaH=Z`wfHqGPUm;IRA{glZ&f7ESYn#T`0UDEOZDW?E| z&W};!eD`1>9d1Jy4>;vi!An7%5wav5Ds+RayXt^DHU--?=PL)(40FDa$=hccCUrLx zKNyob_A6nNI!@l)37$K#<7AGNGenumTmrV~lR5o**PG07TE?$;IhPChdUq>e7DRUz z$Wp_xgYWCz?VZrMU+*%Pl(n7XF#{CJJjW|Xh}xUu`97$;&6hxICu;G|k_%y$t#Y=!_C-iuC_8;8y#8nskb$7^i58Ej6YBXPL!rve>N_ z`=!NxZ81(emEWrt`-{ciu~-L$N$ENnlO9^9*zOi%TofB&F^&@y<2Zq)sB?zJ=2`3; z7W<~fer&NjEOx)eervI}EXK*2`oXb-`pb4kF_tpLN-S1svAD&iSZtcb4ntp~Zp)1c zp9`ZhcprmuWOsC6p%MLpsE+tOgVdt3_eR@!W@_k%ptbNP4-ZPPsA<^9q~TQP49jWI zIl{z<)08lp^w3nrE;Y7a{f*732&p$W<&jFkkC$1$3-K^cv$iJ}{fHqfuTq~*#JzsmM%nEd^?OBd|#+d!APlAG&Ow%**ctzNBbX| z^dou2xLByzMV5{|kzzl#*c}%8mBly*P`Vc__KL;cve?@e!z#21OGjghI-DzzOM#qm zr~LX^Y=EU>f2wp`9923F$Q7Gnu?sB5EhMG8-C}oH>;;RxY_We@j6))IyRR`7IQvyv-L3p$o0|{#H#gVf?A47(WXwZx#%fQRCj8@NnL<`9-cV?) zQuj4wt{hJ4ZjnBaVawCC|F>+3mWFPL?&aGOb!XcW%`dSddM1)BUzRFniRlvjHj3#+ z{OW}FPMD&CVV}TYPg&DT)|O#W7u*w2(;#aa4byB;7W+0#9IoU$ zH^VeXOuvFDb$VTifzFh`fQBpN816b8kg@SpmBWB0?ei{a%+Wfz)7qoJQB`pJbn%Yg zKE2d8QN#r0m3Z~OybCA+$x)btag>WzHFxZK*9tS&7y5-vJ zRpRzA>o(Y_2IkeeXQrzVx=he!ot6i}n|=HA3hOQ&aL0jlYNyM<_5jr!$<-6LZz|2L zy9`t5?cP4U2KMTDG`g_nJDUzT+yF&leyo1)ks~8K( z&gu`LH^Uw)J+iZU9dtIm*F(Pm`i;om9b<6z?rCVUJb1cSjhthEnuXK-E z>`9Alve<_fqu7eN?P*L=haxKT5yk>%vN7plz)Hs%tNM}a&gwlz09T}LxtcFKt2#$@ zcUGUNNEarX!!Kg+f>DdE;dzh83;C2-C16yJyqFb z4QJTieATu8k8H>4tg{Kpsk6>+!lW}o7H6F~-VBq@I`6gEA7IiM;ky?5*wS$WK;7m{+EqR^rVo+uOUXjBL-| z?WD+d@7DcX^zQOhXYf5pKd37 zWdXN=Ii|mNEf0`p*t@NQF9!?hZ0k!r;FQx!|C+Bm13pyfrdfB@0e5U{cHZ9YMWx|0 z%8QUFo;m(83EnKusiTj|VWlFpb9UWg{6Z977QSdz*I%iG`p<}Kn@0>qjP?0Ew zeh&09^UeUV(1)roPtLO9yICvP%+LA6}!aJu^K9N zo5dJY#h4cA_5q8r^;V3rQaZNdiZO>Ge zqb(f^@RIF(@Y&mwQr;Zq3FjZcRXiYALRW2o@+Qj-8=*+oeP3%vESz}L=9*eBl za=a_%JN-Euvhb6y;#RQH(jQ*aH?@X)*bd(^m5);8j^l z#oQcIX?tpTF4cRUi7mQbDHTm7)-?#PmI|7*R4B$$p_s3Fhegj{z31f`Jxl^}J=Q%K zy|8NCVxou9lT>T0#!IH2W}`=wMo%$DPqFq6b!RKD$Ed5R3*Ijjti40s7g(2SqRXX% z_1Z7$^oR^|x^FJn&~;tvvF<3Ca;Q7gTGN(eS63|*G#|feBG05?y#^OJdkp`YvqxmO zQ?z-P4c*p7S9WRYT-&J{)=9r6Rf@T!RXewR1;l(UtP9y z=>56YrJCsSI>ELteJGyks`JD>(??C@d6QtVE%l39O6GEyD7WC`MXrU32{|Y9xO}E#UWA8+mcT^SIgL+Opm`DIMj=dn7X0XP z<>)`YpIuR2golL=f{ChY8lM87c@ZudGgZTn%jcjiFTz7YV=z$_r19wvG%vzZN9y-p zeH~shhW_yEA~ZZ4bbpwrx~K7BY}!j_HmIrB5)`KK;TW&Iblz2Hco?Xg&c$hbb`u)5 z3N)Q|^JSl<$E%0X@DNZpop(#)(^F`&r}OSY!^1ygFj4hPfM|__YLk2@Pk-Zh7vN#%FJ#VM$|dhhIz3TWB`o*Y$7jG(LTV z#e34HQ1v zuWjgsQmZZVA#hLC*CJCDaQax}+XgAL$lV6%X^~eAQf!g@h(dc|ZQGQc98O*hlgA_o|xz#`l~r|N8x1qSJEk(&(C)gsRtq`yTzHVA9J z8h3ZI$RdZPAydXW*ApOlj0Zi-}CFq`Il_;T>Z$n5}Fjh(1pNN5m`eq zzjWNfx0j78p-J&;C~Q5ym|vc&j-~+?niRi=i7VGH=9iAy=+_YAN@!C28lK`8^UHH} znsFsGDSnL*S26s$`K9A10L~@GmC&U4#R}rZ>*HH~zr}O4(zp_u6u(A^D}R3J7?OT{ zY+MOVieIc~o?m6}jqc{TI)IfAN@&DXYY@J4aGLSvJ0`Ox?Z`a&zQ-;RwNL6TndLxh zuaIk>HsmUk@UXhFMD4S5zn5vBGHu(oeJ5!W#O*uDMR&neY& zO7QJV>+MVC)D#XqC%Iu>LyKD@LJ1Z$&8%yw&q^|@VP4%FmtuZPbA8=hTd^|0HH#XX zYZ_)`vSlsIW*2b2u)eur);TppM()&WX|mV9kh@gcaS(EGOSlWS9OdkVb&#_cX{9h{ zztUai>}gtI&e_v+m$`WAR@z*=v9!4`w&~5fQdg3-b+NR$Fiub09DGQ3l#5sCNt%OK zX^zsb1&SUrWW7m2QgqrsPO_h6reg+9}3W`&O-3wI3)gQl#7Nsl> z(P}0Jo96}S$}`*x^g35>d`jqi3vIMI9pRaZ8Nx$7l#pZDSW$JYe^H7y%Q5752Q=q$ zr2?uJPuTq#loK2s!%=DdKmf()hVkRl-A2$1A0TA16&=QJ2IhJ_1}csF8^({ z#k(BwLvdjyj338in>fDrsW5(b!v15>-M~>j6w@V)-&MdL15FLb@lcuKyABo&pgELd za3~Ig!}#3?{1wn#&QUj1ru>+K^t&H4yK)o@Re~psAD2jzFO@h3|Oqi-D$P zw9;kb$MCHm<2Y9yrgYiD_aJC`mS^X;I}+l83QS9nQ94d3!}4P@;>vqZUR$hmMF?+L ze18V(3vP6r18-8gY~ec|G7S!fh?5YO5npm^O2!rJi_>~zV$9rUNDLZ3m@y-zMy;B&}QPtWx~Ich9Bob z@i&a$df-ve{Ke2Q9GSwmuiGethANET-M|Nd?qx%pDSXH_`BI3Qt1|J++b!b!5)V}- zehl{?42=-tClkLnKzCV>0KdTfL0#bfK11X3%XI(ED$qS;Xc;e|3-Dt(e-|{JdwThi ziC-~j`WU)Q{9@oY1~gN1;8zctv)bXu@O>9FKgogLy`Wju4nKzPb6RMyPzF@?5BR1Bfp=3?$_<`8w7qYg64BW z$JEIb-_DR0+zk&^ru5^mWe8}-2kB(oCr;&u=`sT}jX}CVc`gB6D`-t_#Fb8F+sWjKgRcD(98|eh44#)=KDdq06&KBUeG)hqzmEq zE@=J{qzmw4dFk0J;taq;l`X#GKr=Z=7vRVImoR+1JK+RqzmEq1ZZ9g(uMH*7&Kie zZwqDP5yEdEXodyp0{oc2$AG3TNEgEILeM0GbRqn12hDv!x)6RZf#%I1U4S3Ua|H7& zzsl6U^a9-gLu=C|gx@&OOf_`b%3nQb&Ipp8SNZa?9}24N5}<4o%`x2 zAE5dqUII10aaK!g(6NJKlbdkyS;M&v^G=VA!|~V+xNTV^qt_s;ysc~`(yXRt?vSBn z_~Ih_HEgs$#F95a@I&c&bK1z^=IXSuAi(uWoCpiU82rg}wOZgdwSB>_jLw_SX=-Ui zTyf>M7xnoqTw_eTaqT1UUyg@GC+x1YiGru!m3F=0>35}Z1YZ<6@mJ2O%HQAm;pR*4 zf8yo&C%}_w@SrG?e#hA_1y8@b?eE~j=8&oYk%~i~g{QkQ{}JY0jF}SrAL9LUM&f@r znQi|~X10_}lL~_0l%k`x1}n*+umyqyh(D-1IyUI(!Hu>%h42aTuQO z0GpR#c(yYPuK-1eo7a)mdN|w)*PGy|`R{P>F09^tnDieOUbuHWi9>$vNxaEvB~68c zn4*ij>GR9!B`YnJSs75JSoTIyI>AF2KR_t{iJdNs5tiHNn-pakFHdeC@l&eMj>dxD~j=Xicv?K_Xs{O zq3R`HJT8DK;w<9f<0OZuyHS`LddKgYWp&lPNucw~`gPjd}RH3~Frh1|6 zhWD}35n(}XZqrabM3*wE{EihDIS1@{fNe$bk6`lztfp$FNeNxfZs66Pk12 ze|~_*^Jj$kQyj1#f%l4HhNG|82mHX!6Yc58-QvgCRQE&J0ap~a!EUs;9~iJ#|9=R3 zriJ4K-5)CMX~#1`Scp>MICPZQGacTbHDocFADYG$68|=!y3#ts>3{;l0}#}n>1^3| z7500jvLB-MjJ_`71iT-j-qVYl@K78%HF$?g5a^z(pgeGyS&$M0Wx<|X*8z7+Wie#9 z1d%DEq__MY<#!mKran7%kG2C8d-JMXcrD5gD6V&S2)sS#B6On>(E z{8BN+e#i)02A7Kc0q6sIr_v1dGGU1L5h!CrwT#h^*MvtP6NagKrqEx+K2XMn4U;&q zjBX8cKSb>rN9F>*aZ8EAF!i6Ac%Vt6lnhksHdtSVhiCVuIEOG4t15%XR*>iL76ps( zFil2!p^F?{Q_G0vF++GZIiOKY@nWbKgBQfU)K?1*m)Mi_6tSyIW$h(SQmlKYT5J7d zy8KqGZ^vNOy($RT9M7zui43hQj=?hXiIuSldU;PNsN7ShYGIC{&F9TLyv&E=gczE} z$&osTcj7eRovrZXh-rn3ix*jv>6jN3i>G==jtL3BLgP@kOtJ|EDE1+7=E1~}tI+O5i=(j?D2RbYJd(iKNz8N|z?+4J=LdVEF!Djtq=*&gB8r!IR(xTXOi=AssdaRVXy~JYQv2?dv4BHjr8zy-c zd(dJpTI>~zA#F|gkebFV;$<+zz+n9>Ho#&P78`G|dW$t!Y?;McEq1%b?y}fp7JJHK zZ(Hnri*?18h^7^<=+SiHhrx;+WHEjstQbELR=RqNHCXIoi(P85+bnjc#U8cTlNQ@( zvG*)ikmveaXiQP(0E-=Bv56L&Y_T&eHqTux1N z7Rt>u{BlsW(4&nEu-l|QfZ=Oz9;!=JSuRundt!BOKgv&M5W1k+ml zY{JZ<5l%OK3>~gFy$2l(HgS>z9-M+Sg3YF9@ob$nYgS?3C5#YfTR52qULzdq$*yeu zN_ey$)337i8~K9?QQ3M-aLU$WQdPEoYkcwBkp+)39ElBJKqs#~`r-J(3%gbp4(e7S z?<@IUQ3L?V1y`?a2K|L+#W=w!<@;9tY$Vtq?;B{WD<}FgjVD*rxQ@nSYWaH(CP&B( zOpfBK_ky?FWb{67?}@TLJTUvATtpoxPlMjA2nJCJnfKQiS(h?7;FA3)_9+%{@a3QP za8glGd<@--+p8lS94`=Ro!EHupqnvS8CyIA{zRN+$j{9ex7Bc~>gEWKrO|=&yoEX} zWS=uwtdpR2ZCmQ+HtDdQ_V*nUlt-^@#pfNIZRv*UN1wE@315g77Y#QxKOy=D*w z1kN2|pE5B4e@$YB?qRWiJtgekaI{)%mj<|N+}dEr&f0N)EQ3D|v(i-z#{(2$v_?)k z;M0OyTs#E`3*+PnulUmInpprRN3;O?4i$*`__AKmD;CWj2497d4o5Bxcy#1KQ&fh$ zicK@NQ8@}qu{joFTcX&-7Q5MEw^{5Vi#=koKUwTA7Q+b3@atquQ72}x5{q$CtNwC4 zMiWL`7CY8rb1c?mF^*EyEk`Np_EwAi#A0hL_JqaWvKYrJ>NXGK0p-V!bQJ4vv4IvF zXR#wKMwu&hd%DFITkP8wyTM|&SZtNW9=6zlXb+WNsWC;_(nktUdcW|IjYU{}!m3r{ zi-1l>^So(Y;Un){3g9VNoI>F7!bjeP-uNQS&#UF=*SQGSv|$?{E{#2Y^EWKsnTbsg{w0^#bF4q!G zLI@j4jW-zlCVB(IjR}-EtU|uN2DEVQCS&0vOqNYp9uzl70yhSd#Mdl`GfiPjr6>TwyCJ#i4=jm_?jwI&?@`8fCg;beP!8s;OVp zR5x#?G^L!&MjYU1I{kg}j1KH6hl;J&&wBmvj1FG^G{svTJ5hY^?(7R@*TL@=@qcY3 zA7|%G!*h=_#_1fH?#zuGEi~*rwLM~WZl%nE;x!v%!d;+Os~-LTJ@5K95=$KTKK5-`WQ=$I~`f1R6gI^7FmZMte?6&Bic3U(>WuaWLI%6B< z8D56&B8xH8l#cnWZrR@}_EU>JZ80o$7`km1!!m%uC^e>TDWjtNMpFNbG2+N3wBMJ2*_Rn3PinM;IYk1S$tml|%= zI^l`qL9gSK;Gxm0T5XJ*Ft0 zd~_qM*p)>KPg;q#=h0#KEn9yST0#7x<-%{N{Gxe+xmtc}<+q8ymyov@mb->F*KoIM zSm_$pso}LtHo(AXNEb{%2Fd0O^T3;caDY)6NOKA*vq|7mR$&o-L}f_x>GiW3o9pMz zmF2@jL5&;WTNc#>TED2gb5_CX#Ji8Y?GwEPFAh6aDXu57<@8#{&UhbNJW2wR+H&q9 z^cSNU@vbT7_H?)W-Mi&?E;yoKzm&hh1@7O3P93^+?CM+1#mHEE<-ok3a9w~+gQIcp z-6@=~NyE=#HAw8zeo(CBK5tks39z=QNr3yj0hzW340V~Z+UK5W&2q=6R~j5cvjmgr zUFeMBX6U;^{{T7z_aXHD=AC);5#CuY(Yly&NmEn?Qi{zrwo#rGXz19kDBYD7`+>zc zyHK~cTZ}UX#U8U5ml+k~K9TZESZs;KWcT%i6Hlr*vErooMeo(33Gna0E-B&1-@NH` z1@x-qmU!}eCF=xwn+N4`MT?uS)svE+Oh|5)$`o&{k z7EeA!t5V{3(>;&al|5Z`jw?mQQ};?yc+*C*i`Fo7yjry8v{P3z;R_Ire4K`^5!BPt z>+qKEu=$-MCRP}%<2qf@f{Y7PsQZ8qz;ijCJ)|7N;AE&!?)NfMLC`Fv-$*h>iYliI zW5@?R1lQ(yMIvaiby=fj*{eZ1DLfGlO2xrasjRwsVD5UTD6WF_(PG^o{JkZBqkWZC zw_LfjplYJfo`m;_0?ZcHES+cv^bY6o#gk#})f_#$oH>$q8ObCN9wdC0p`TWV8f1d% zkOhPdg8ET6)9(pun<}McabPXiL7BPCv7&eaycs8Sr(18zjYHQPmbhRW#S~R9_O|X= zc~z;GEVNt>pzIIiUs@KSYpIk;@GfXeU@1-NZm?y0!jcxE%xxVkp6y zhhN&^(iD}gbHzAURBVBzV-u$s8&{>{fJw0*TZ{uH#n`YZ9UC^qxU{3#D;8t@R_tSo zMNlRb>u5|-hx2^Jxcfp=RIWf$jD=jWQ!QPc#W=fHI?nEu?rw|SW3e?Bd(>hZE%u(p z{%JAfh~XE@bNwhWrmz0JiZhUk-mry7d<4%%ycQJr#6|8^Wc^Z=y_K!0o7Ga^jL}Qx z)^-u91SfJ33lWYbD2iR%YjOKav&fw8FOC*vYH?#?y)e+?#(Ygru*K~ov=pT2BW|af zcQ1Tw@#w8-fjOFDi?@f6pKDvLV2hl9eM*a*sRh0mgt@lB%Rw7xfnB!cuu`Qh=hb*2 zX&iZH29Yjlu#s&8DH~ax4L9Rplx){3?h1x%Y^&9`;4cPm+=#9P?r&gc<2|i`ZL&nR zfn}-CR!|$*1l{5BHLy%DB{2=`a!cbiu#CPENdqg*IUuHnG^jQH7S&4-y<3s*=nU-L ziUZJcvMvmUJ{bD`&>2wd>B&y@FzA=!eI#_YuyuH}g{3Jf5(|o*Wo&gKs@O#qyU~~m zuoSFZqRuZY_A84$YcaN~>c<-vd&^>n!$y#XhsxHjDK`TT~~03^1ms(=E@%`1K)ewS_IpbqE~K zIs~2+HUysJ4T0lddlXCTZ*k_9#}=4~US?WT-*IR<9FnI@TIRi?U< zFmHD5D0mCJF7ri>b%71Ge+Yag8sc%lAWR`c;3nuC0?#)MG*%Ez15HyDUufv*vIS1F zF-7H0H>LZg#jdk-H(2a0i~ZbU9Qdl+r!2;SuVSxRY^%loX|XOStV-9-n4-@97CYEt zoCYc#M=vx*c?P<{D6pm2cP(~>#mp)y(%^oJJ#Oiqw%Fe+w#8x{kk{&OCu72<9NH+w zI0ROItCH(aIPRp1<10?!D#e7>pKScswryCf*Z@xB3kTmcWgA|T9T9FPK5R{V*?251 zJjnJUzJeHAwW{R3aRSNLAx_Z9IX?t5-h?DMB&M-+5l^<(!g^A2LzOIAv^Es+hS##H zF^?90yA>UFJh^lV2r3E(&tHL`^KOH`g`*Tl3jjGGJFM zLckzZQRX~}>w`FDh{OvY#XbnuOW^cTko<5qNeV9nG7AC_tMIdFl0)OO_$gaIsYtb$ zYNe``t41dvsa35>wAKW?QPXm3YO|)ht!bq-tuv4Ip3^=VG!&2!c#^sk~5|_qRF#l$dm?=LG2S$KiMCu_$UkNV~kYG=h zr8i>qWcdMP@F{gqiFy&DPZ6t6m#8j6_XAJX+Ofr}Nd7a4!Z*b5WH<#9%cUf4v@1RzY`nT3s8$cj-P zU5O+U@7>5twEdCH`D+4xL|{KD2>qG>2@v?404ag*2@rPkK>K7A8?v(iYKAAu^yRqj-6U=5w;_$rIFDEvD?v3%X zK%e#n1>*b;g7J`MwdPOri^zR`KY>VWoh+a{wS%49McE^S6@9&d~<{X^lBz0e*Z zm`$sXj<-%^G2gTr^|I2$8O#4rdj<0&V6R}T)Fc#mo zs<1D27pk#E-WbC(dozBTHo!@l^Md@oC%=D|-;eOy_$hx@@mrLKPX}<+CY5uF+ z1qTZ$D9pM|;M|B-QJaHj`{E7a08%TOH)Gd-{wv+^^Evj@-v#yjf6}l45AzhIw-Fo4 z%^%Vgf-j%mNLiOJZdlamm9!76-hW{AmfG9Ajtzvb)VSpZ-x8IVv&^jG&uacW#Gi*L zrdGJLlwHrVdrAhegrFfq+~Z?jpFi%m>}4h#@b|*L<<5lG9{W_t78*K(q46Ey? zLLfmROJWEJu2FOZBZ~Wm8kcb#myvNBWKe@B;0~^!qEXSoZE(j8_}=$a_37m%QRn;P zd!DZ$x2u0ur}jQw-CbR0(b`PNR&PW+tizJJo$Cs6CObuoKCR8Tcn2`8L z@n%N+9uK`%M1PWo;yJqm%@k-w>Z+;@ZZo2Zpe1ZOA~! zexp~d+C&ryRfka|jqv*pZT$s8L%$R*T~dn^vL&TrE=0_wt5l#%RI`K|&K-HEQZa3Y zMhPgC?NBIFe#1D*C=$$WU7eGUVI~}p=5PQD#{)SsG99)vW6|G`#}Q95r$;XxG^nK4 zmqm3i74F=^L2NeljynYxBe%X!Gg#5E_0_3Gb$beX{an~<_rP}xFWFNwX2fc$s^VUs z>Xh9=)mM<*5BjRQWqrl(3^8%`ztClg{h7uUC;(foxQ=7yy0V;nG{ULy9$k+fJ8xNW z-E}NhFZbe#xwUfAq!A*K{we<4aP0;aXC+e&B2FT!lp&_I!35u0DnM zz!TmWtz3blmH2aT|1qiLk{>fJ{t>m!HrX4{DOoypPjTJrMQc85RnqH?qPjPVI4a3U zcehiv(O6|UX!C*J#c{g z84cyR;V~XJI=mx#o!-&`K9=7vHloysVI;4W z$4!CIR_eh`I6A6|M^G7@xK=qbn@8W_h(o%Oxjgz6M?di>pDApWlf8k*r>z zd*p4!Rbz)tQ_pG3nIN;;vidKmX`9X6xovYf<-MS7K6k}!#}STiJ4NDo9hI`<1(M>n zRfUT_uPu_X$smkPN~kE#W5ap%QL^;5T96T|_*;SzM{-Hs+a#!;|dv( z41BHRlGkd6^0=h#+2USnitApKgXp^AUeA|Aq10{vU4i~<`!4$J$i<1NMZ;dJ{Z}uKOEF@4YGeUXQT00o>L1)VO@!Sz6|-hbE*h0e6|rg zzV;t+>WE2`C!V@i^7_(2D2$l^a2#B15GK)i9nTlfz)_;JD9v@n(2e<2CeaxN7iWzm zI_0>fuMqY%T(iW*$!Fum-2CU+x0z2U<)qVG}CB{{o+B|ZuzW;e$g zi5VRem!)+P7IBtII~OF6gz1$f&a2VO6K{|<=Es}t@@)5dxL6DP0Klu7jy3_6gR)*}|7+c=@a@pD#IaAT>dJ8#4Zu!9`@;k5&sMwOaU*?Jr>} zM27E1OXT?Ge7MlQbqEY`&Z*8}M!|$(M&SP%3lc6-j#LnCZ`y@M9!ire%8c`-z>QdcKI< zl)yY3t?_PjvYq4nEjQ4#+#Zyy5AN|eqqn`5T&4+C&nYu2<(Tq)C*>=VvW4@@PHtLl z`c$dNWr)zL{=z{fG33VCmud}(QKUB-HN}}T0IFl2tc=r_ara`Emc!J}y5`z1#IlGLFL~&J1M0?Fm@Iq5nupgEKZKivQrqQ0EPN(8X`= zBTj=v+q=~<&V`YV37O903Dwc{IJc=WO)|0!1W#I)@mvZ1Z6wvni42e2D`jP$nIr9w zug+DhaNy*V22QrQqiCt5-r8R}GvSWau|?v&&F|@bAohWH?h2M`fcbEr<+@H{-doDa z$j*}EYj9@F62|7G2{(T1)!N}wA?(nw>Mfa$NnNmmo4UwI`xjO@c{}0Q=x50>=d+YW z5%0{hoq@$^ln60j0+F$E@N-vws-A@tHc)xq5)yqRz3!4e+pAcP3*?x2+$mAEllo*QO7P z%rO$4Z8}QAb7>3nxkFbu?jgrKJ#g8>mKc{!+hWXS7m2cyKZx{EU!!K*k^~xXplC)G z9YX6Rdqsu-6rqY+r>3ng4quz#2}P?*7pcu&KZ zByIdBg83G)9s$0P^#2;+*;ua~B+{y#^JL`OglnVh7-ldq6>Ce)ddT%SKcl5OkPAZ=L%-ZE5`!ZC{5t3c@fRjbQT;T)ioOO7L2&A;6&aajr zjL&z9_|*9q;@>xt>+A^jr~#5KwqrlZ!dtkeJSEv;F_WZid-`i4tg7FWn7jFkim#y9 z`mE6omh zV^npXWID;0Bi~tjx(FCm%o5%pk#0m!2sNgsiXRmb?=$P|ay&u`$vm7d$ARlvSk;~@ zsr2{PV_4O`EJ2!7wJdysByyrZhOlb=$i@)p13uOIllWI+$m*%qof2)EV88LH);#ea zrw#go9DAzudfzd#d8Zurh|8u=wZiTcwqgDtVb%JG1Zf}asROmA7D^(=LDe20j6Ll+ zVHK)Yd7>>87F4T!rE|oBQG052v4|{aTCGwy%#y5~8Fwz)0(gj8k44Fm6%R6F=fYIF-*_hV_QM!%=gEo`RoB6+P`{qE4bUZ0ZW+!>vi zysTNB^P$M?Bi)LLtd--NpsTM`ozqt`{&&n+<_ca$=e#W}OYeV7-CU6}0rx*MaPKoC zxtXEi!6L|SAIuVTJte_Nq(2%wP@$eax=2JiNZQQfjdE3<#kF^2Wl6(Yi+uJ79A z(_5>=zY0S_Q$}{46;j4_K^dRk+9NXNOB(j?TP3`A4pqsqHzYhtj#J~Z>C;7 zsTJvlh`ig7lgy}xSNQIdJ=3{aiC@VX^aO^eM~Z-Xf-~D(T{&IyPB)%PeaB;5s9|JPw<9L)?8u5)BhQfUW-S@`#Y=9o!u+j zxgxhhF4zpaTq}A-!c=@$AKyrah%Dp0Ol0qL7DJk{tmIcEokH9f4RrnuACtb@c+JIW zKG#LFd1N9M24b!8a&BV1AR*UTE`w@4W!XWv#z~2Eka7_?4ri2k zLb}mujW4{|=g-6ALx<}d&8d*5fh%w{F#N4=a_tvsN2eVW_;+xc`|l`z>5Er0{*w=J zo96z8(L42c);Kn+#1}7@vQAEjE?Ss&KyqTVU0P54?v+-QR*;+$jlm-`ZAMyOeoTzW z6BE-4aZrH2erX5b_h6>j)_2O{KEYeH^*{0`wm14hXvxum-m0x_?!iUGo=Io>YMDcGcip~tPMoG2Mk4vY)q!1pK zX|3ULn>mYkeOe=B;Gh@`8l<5$%)qyN|1Uy~@9$?7@-^ex~Ki zrd?5%)jLT1L!)}5fTr{N^?WzU@GY=o=C zyV>zvvCVuib~B{nWqXGBx0kUcm*z6BfTkpk!9$ly=d>grNqJUs;_o@E6wf} zf0ozp?>(&PB=Lv(sBfj&heSTq$L&h9>>OOckguo$tz)uR50AG*Jk))CE6tuS{zLKl zC6oob(kzoWT#^Wl%#7w>4P7Qtv=5fhx6n7cFT*CGQ2TTb7msh1?gv)WrPb72x-@@lJWA*#l29 zLsjb2#$6=GwW5uKt#0a!BcEd=OsH24G@6b6r;C5Qwx!=f@mrS~9yJBh@@d~qlIOsn z5Zc+(zOy7g>JwiN?eA&X4I)20bJ}tRJPkfqAW{No+RrqSyYC1OHsUqL3rrT_5I3VuRbexQa z#pRpTbWCD&Q%QK5?q-Ric}<5KNo@U_({xYU90oeDr|CWy@7H8-IXkS$64R4vKTS?b zPfANpOmA1aG&vgWnw*S9YdE4zPfJfb3Oq3tJB&D?*eYe|8mhPg`Rj*pu~d#UTPOF5 zrY3ibCMIVhqzpbg2I|Z=_~h5CSd*f~!RJ1b?aL7++%-(a@%H6d3DYsuv_{3yzuNlq zF4{l1q~8+pdppKK*=}3_rpS%MsR@534Pk@z1&R|(bG08iz8EMXENtk*z~@y^&IB$?2C zfgL!q>V}Aa=-H*G@?Mn`{uwHzr?a@qG|q{jzfa|D7x_@`Jn{Obygil2<^`R}i>z|^oGvKm-I^aIaxEKFnJr=Nkb#T)Ajpk>PGm)V{B{t? zTgyj9Hr)G6+tB|u@edin@M*z*;vY7Y;tl+s5dXh5`S>MJX5V12bCYp;n(;~T4|O-+ zU~r1~2aT_AAX|^}tdZxX#{~P5r|lMtXw%w`)p1o*N&5`1>?i&=gqqV+xOw8=qT!W; zB}ltq6uv>?&Ej99kLTQ$eiV=V;(LG0La8$7NN{}Ra+ zZ?WB6O?6f`kt=UdSuJwQMUJ=EuG~p@U>H{#pXN;zxt0yMtdKCFzUv!oP7?o6Kk{kb za`6v6^zaQf&uU8Er+N1g|L|?O(Y)+T_ltk%uGG7&&J^#qp^o5b-Y=!aS~lQvT~kST zn)gSEqIm-@$J-KkVj4Jb8;C3NnvpY36h87{gIS!v4(sN;x5*}xzk3-uBgMw&_>EzQHQgh zO(0!SX9|#SMIC0b9%*s5=rNJ;lI2=GF2t2KD{Gk^W9loxH~>y;#q#BR{%uUwm>A4_ zQ?eBZ#K+giM9kxBckM^6Fzjxe+h2%-;rRQ~^2G^GE$98?_NJDTz;DEU5%#xY|5xn) zj{TF^;|@?v!aRWe7dXBhdp^$QF^5V#u11`9V?Q7JzhZwr_VnjK@qX;zw8tD6(!Usc z`g3@H5B4Y6<0aTXh+{sf_y_iUKKxJY=VQ-&HDLc3_MF4|IQBQ9!B=9>xwEUV=OpRX z*ssO@N$fdA3pY=-jn<#@Z=b=jOt8j!7o3P3#r|i@`A(R}QJe;e*gt}O681bTaF<%U z+8*Mx1m$C!UM@*i3T35`W z#W=$bRW@1~r_-DKad|rvu2fmAGOi73!YxyFtun6nVPv`9hY9ztvJaGT%xuE#RMr*! z)v)f?6>|nEJ46|8IZU{z%GlQpTdM3KWqh_p-8k*}KYiDEm$szM`@5@rnF2DQ|aW z`z!0GY@o6+%8pi6p^Tct#CN5#Yn0ut>@H<*DSJoRPGy`GY~mY^S*diTIr-KVbBdLX zQ&y#{M%iLzoat`jyIa}4%3e|SnzE0SeX1-SdduV`)4H%8jy^EzY@4#}$|9KlVd6`&u9&m0vICU$S2kGLXk|spIEU55cdD`qWwVuW&Y%f* zv$A`X-KXq%WiKn+qKuP+84IV~yYX>Ci(x-2+oh~GroWhUbFC}p9HZ=bWpk8OD?4A= zMau3__E%+Vls%{HO=Vk@{h;h;Wl5O7WAc}3T`^}bWu28Bpsc5|LS@CuW-6;xcA2s( zl-;T99%YX!Tczv;Wv?jvOxah;Vi*gUaQ5(6W`0qHYxi;*$!o?7^j##x3;dBbC9xL%0??IQZ_@`EM=D}t5bHjvU`=S zRJK~#o65E*`$-wUEj4B9gfWuIb2saX$#=4bapsT-cZ`NRURkxW`O2}zG;E5j2eo97hkg3eKPfU^F|1}ht{>?CDn%4R65QMN$Y4a#m&wo2Jk z%C;!ms_ZvqxL2`t+ReJsoNQ&e$_6PLr)<2kDay)}RVk}cR;%n{Wp^q2o3eGvUQqUl zvd@(LtZbJu-k6&H!f&Wef7w^r0m|}~6(}oJR<7(~Ws8;FrR;CY9#Qr$WgC^fp=_J7 z?aCs!DK>fL?Xk%-zl1bwFJ*bkhATTs*(7DNlvOFaM%fL@?pOAZvR9P7rtAx4JCxxI zP@6w|UTO2(Nm(~#`N|5EjZ-#WS(&mK$`&X)SJ`4^mn-|Hvd5IIQTCj&ZOXPQ`(D{k z$}qRwmMz7)VorNyos=D+Y?QL8%BCy3P}wEQu2OcLvPYGzRQ86l&C0eb`%+m-dpFPN z))jL)DeI=JhqB(v@{|o%Hc{DRW#=oqNZGB*?ojravL}>1uk2-ITa|sN>^Eh2ac%q6 z-qw}o?5nJgvi{1(DmzZuRAtkZEmC%=vTKyxpzI-Kk0^Uu*;-|vDEmxVQU|v^u%dx2 zM`vYwD;uF~w6YVFoviFEW#=fnPT5V$9#Qr$WgC^fp{!BaHf6h&C14$Jqlfmft~6&q zWdoEAQ8r%LNy@5~%~y7{vg?)Ir|cifo>KOVvQL$LuIv|OyOp)=xwx;l^w2Z ztg_>j%~y7|vdffRq3i)=E0n#YY@@P9W!scRI=lHxvaXnurED){7b?3%+4stRQr4-9 z8(%l;iaEWNKjTmDMV{QQ2~3E0wKQwprPG%C;-}QdwqKH-GJ|E9T@X8>DQU zvhm8Ql+`G^R@sfp?p5}HvbUAJt8AyTUzK&}=H{=9b;X<^%7!XCQrS_;<|{i}*>%cp zQue5_mCD{wwprOWW!sfy?(OEUy>(%2T4g!P#wi=GtVY=aW!EaZQQ4!)Rw{c#*=A+m zEBi@V`+eN}b+RrzOH+1;vg4JVsO&6d=P0{g+0DuxSGG#oo65E*`(D{k$`ZS~`Ae~` zm~)Y`zbLy$*?r1hQ1*(l&z1dGS#q|UM$EcmP6uUOlnqffRM`Y&rzo4R>}+M%E4x|Q zWgjWqtt?@GlPi1&Z(SId zC_7Bq2xXrR+Lo|5WyvvQ5g~RQ8RsAC%E@-86^K$J<*M>QC7qW#g5dq-?ITvy@$<>;`2I zD|=koCS`9bJF%ymmx!<8!WydI+sjO1jWy-ElcAv6;D0@ZOYs$V- z_KmXEeck+JSr_!KvOdZRl@%*HUD-@!XDK^J*(SIa%DMlhb;X>Y`nl=;W?eBS|9Hoglha7iKJmYcl>4ojUwZ5!WsFoh7bB{CI zKm1*ZzrFC#&TP#rvsgYy%+BI14n7V}b{v?2!Hg0ADv4$iS8>F(_fdm~u&!lBn%j%B z%*gM8M`VqK0D1(rS`#^P;+lQ*);u&Hh;wzpqb2NQnGb|f0>ipX;&}FG3MFc;Ygj13 zr$G0+_Gn7W#FL**L+4<-5EEINw$sSw=IlX}j+tEJhRqdO{+JaB*@&DP%1JlY{Eizm zFBFvhz!$V?-c-pEClBOH&^ekTb4+MbVONtTkW^-h9M{VmEOO0TW@K;WN5d^!X5^z~ z&U#{3Yhtsro;cmewai!#x0%y44PPS|i;MfCdzcAK(&PbqGcwBw^JDCMC22a&D`HIt z<}|T7S?$L}yg5y*H#?_kZn>E-#rm+wRAW{ai)zrHu*}GFfn9~?3-qUKn3hnR57#N! zkHdZv_B>Z6W6v-X@n@#9&}A$$8dhO_W3q~)VN^mU-1XL#=G?689%c6_dq&whWv?lF zOBv5^lg1CqBIpx_C0Q3Pr^@zIHbB`BWv3~ds%(j}rOH+)dsG=MGn#ZaDC69E!#L54 zu9!p1jD|UAF2k~+qYUHcHHN_~P0^BxDJK>#`f?m?+15k4sBTNql2Kn5*8M_qBgj!p z+ou9;FR9x=v;9xkTLl2M!Kt~KtBh}2l6=5pPwV1OdCa7hMNd!7PY(c>ns zJr&`m;?J|Xh)G~^Ru>l_L^}Rv}1O{`BF)}*Dsr#U&3(yWz=X93tw_UVM# z;^%43;Z12us+x`>YAh&vn$s+W#q%fPKvTLZtcL{VkI_T5aQ#uu$oluGJD$33v|-K2 zmh%PWDeVT$hnLw*4%qGt`UjSEtw&HQzZ#LJ#Y9#gUio0P9&Q~`ea6%^XRA>GjuRgD zlg|n4ert(F>CHgEIHgwwXw;CI{mH&!6q+i%S`8vKot4F!3M)NUiHS#Mjf&MT53z=b z>VbT7JAL+N^Wo!e%tImmlJGak!g-jS$38qCdsYX&2dbTp{khn)UtfSdwcQl_8Er?G zv65)mnK(A=3hPR9u2y!NvOATnQudUxEy}hk`%Kwa%3|ocQ*e|f%Td#XhnmWUT35^| zRaUNypKusiPP;R*|5EmEWm}bfsO(vs|3;RVCL{aD28|3~SSN$V?c$U{BQH}e4H^rr zNkbW2*2$nTzpzdQjj-;0u`v*iL8F-X=H>JEOnm==5hTy4srXBD?#1scak(SNT0MSZicLmWTUh&?7Tu%TW&~@9i} zYknvwds0ZbvLd}<=Q)}qDhab0Wy{X`M~0o_Trpb(?C-xn>~yv641{iC`<-DYEgIen zNiz&(_rSWQ#?-eAM15VrZ|>V@Wwz1&NYhvn$930l?7NiLKV$0Kgz<)=zHz5J6lEP* zMePnnS$u<Vy? z*!k9#=3JzVahP!R${tX*LfNazURU;kvX7Phs%($4G@Pdvxp`f zZ`%x`SwzETDx+CM!){RalrnyeYGglA_L;JumF-ftH`>U=x36`@oc_uNE1LoRXTouj z0h31l3CB+`HWN=QT>3yxgE5(y51EXft8+53FUaWms90w3KTo)%7PSLwha4i8)NLuQ zd$1m^;<}GuQjvq|qPic7>z=$9F4$6p&BI)pQKZpCSjwn846?BDlAl?)vJv+GGI&Je zG=+;ktu0(KJ|~Z+YI+pcZK6PK@v!X~mwwVll50SO%uY7)MH3g!&h?|&+7WAF5e6?R z-&!*IUhaQHN-&^e?JUxeB1&>`jzduzFJzc?w2(mqe0lE`W}02L*@?lW_X_jP(Kxf4 zVs=%sTU?8Tjcb{@>ea=rXM7vfwb8n^E^dU2CKSJ>twEYbS{ISsTdeNObG}A7aa{R| zz*k_RWCwGPM>h0;r6n9J7poYqU89Y(Py{PSm7l}wZZVtz<3-;_V8gHx=6X2zfS@%Z zh#(J$jSVa!2P^%Zr+bGHYNNY{sAWB#u`6K2PVVTNWI(i+kz&@QdQS~-W zsJ(zVjE%*g;4(J%erDlem*qEPQtaD18!wV*=a#aEXIk=u0Ld65eDP@ zM&n>!5q9Ln42@fM*vg_|No#5l7OAYML7JNTktV0KybUZ9>*<2g%cQ_4DTrXxP^bYK zwgLQFiY}#O;aF;8_6kL(5xwSZX|f*J&}{Jd##Z}^(mY|Kk}$cr4U*F8Xy;JLH=+4$ zgG*~aj}TtTVU5q0oINC1aw&9iPQF+#>cI0BhQ8LQt;IFgielAUuzfcs8+L%IJ{SvA zigaujlZ$VOc|}?h+VKH@wohLMt2%K;7NJMbXY!mK{P_=mcCs>QO^-Q^H?S!77p20{ zjPV8*KR{(jFNMLOpn*jb8_z2-un6hjH?Rn6p+gHi1B>X4O&eH5X2q(W7+*wtyY>~w zArV;Qu|n(!=wts+?JJrK0CmJisN(83&_Vot#_cVQ$fj6g-0`7nZ1H2BL}I`06Juww z53X0mOCHV1GZ%yl${T2AaqNhvGNJEEdhLXH+V;bYkws|1kdeiWFj~~Gotn|LvABtu zDsL#JNv-0#@w^C4%E?|g`XQ%o^aG0;5|)g9ppb^M_<0F~_Mvc5-Mj3V>&BMU(dz4t zbtS!E3hIK<4aG}OV;`zoKbClX(V8z>Nr$W|+Cy`9RSm)$7`B$jYvdT60_GyeWpuA) zv2}(InO~B z>E}6L$?q=t{Xu>|kpNre_f7eInN5H^i+wHVav1TU9C7No1t*1Dv-}2yOk4Kd|YE zB3JUE16m}{*-n0LXQu4@M0ZVRrt5r7cUk9Lx*L(f9W)sU9l~Covx=T170RZtS;c2*RuLB#^k<4TB6=F% z1B9BVHlW3@Nu7~4&M0eMu@MI}uZaGrLB@9;2XC>t32#J!!yPY+xv|bu#Q0ceL~74z zk%B)%@}edNG!ebI3PE>O!YU@NX2yo57;ZJz7hNNo#*C|LHq)44qzFXi8mxviaf-=R zsby2gI0+gc4MWRu8YZLqEhrvzUuhv@pI0hfv^y>XJHDmY+w2m~dimw3V`xDGuR}u% zK6Feucl?0J*@lFhvLv7p`asYN3`awmJ75G313e=q4NQp_#PTi&qKKIdxzR?)u%=<5 z8lGok@@l_><`6y2Va#RPc7=IRnrBwqmk9U*#`KI6lA#(z`m~r2G)IjqZ#e zb5ST-^aX5XZurI6$}FdOIWxW$3z@tzfx`@(;V{E#ILv?>4s&}@H0+0rMSO5a8aBFPu*C&bTmyA&TA}&?M+@#k+)Y% zdOf>}*HUUUj*51Ck7{!7FK~ZiM@VbYFhdJo%tQ~w$!&~6zYd|H1>d0$(=x1#yp0<8 z#`f~h(U?Kw?pxCl(B6nNG4`h6T&fn+bI|eP%zVdLHW$O@RHV{xB)1%L$&H0;)!c8? zJOd_GhDTE=;R)y;w z*4e;@!n&pGJcR>alCHwuXl|*I3U8QUwUD>kcqdMqg{P^}LcHg<@5blBWsDZi$D<(Q zN@(R8Ej$9QEX0%O^i6erxxBaucQ^(L6_8JKUW4llaaG`M+dLJ$3a;_O+~=c@_K7!S zcs)W5M=0+3kjrd;@cC#nFN#KH^*}Uya|rW=ZTJ9>7U;}&tE_Xu)rD^r@Kc*n$wxTt zTANj~xyo=O>cMe-Og_-LFPRVK{LfU4eYxvIG9oqyy=ScBBxc$i94G!qX1tcZ&H22| zgr=Xhj?9{ZV0Xpa0-m}>Ad`}kn@@iyOHbPy_piWF=y=SpUN;deY z=t%KDCgbMh0;fx>TzsTvOd{@w#^O?0T%hQ9E%1tz1D(xDBa^qqKf5*7_DUqWqKx4g zt@I%%>)CAPA!t21Ti|&vmvQ66s!|CxIOEmyDGBbw;9OVMF~WR88UIYzyu>?E!XA;a z#V7AQ5;XEFAn$v4+tPF1mBFC?muQ8dTs7FBO}s=i?ac5d0~-*OJ;vIlu(lDSDE>tF z@TntxkIJN*wh`GNh439k;1ozB8^d(Q_Tkr{tdRa9Q9ZMK;apibmmT9gk?E8%EqSQ( zX?mS=b?Xad<@s^iplw>kV1MwP!jmq*$~WG;BF48R%A^|NW5?hd&4 zHXbW%X55u{TBM-WRSCbf>FUd2p+oz78xevJz4w=}p1s5}Ic`W!ac)ay7vPkaQ-nRx zI_6x_+BJY@&b5D}9E?<_J2xhsocuES7Q;)YS`%-9+3$Rptx^sh*;M{?~`|HzbM;csq2zo=(f9?K{aa&Sz`uFkn$HY=CR2 zMAM9|#1!$oMa~411#5uoc4VNnc>aRK+}_Rnc?P)Fh`+Iw#d^L=j<3d9F;g@S<3R7m z_Atu0uNLA7Va8UXgHo7!IXd+bCp&ULLWXlr;@oIfYBL79(nQ!K%8t@a65WBm6zVMI zZ7wVFBoQ&4hi!L<9PcOjVIKFBW6xHi$xqkRa%YaT)5_=&X(wNI2ph&ZNOIAlt;Bf} zB(xrySz?Zr_jmC=K{B-)$Lpj=2P_PR4daxF$o|3h@fpUsS^Uq0VVq;N?k|zDhS!nx z+H|YP93$bGtvM2&tH_yi=SVs3A;&z?hgyGM-AFclhH;LRC<7%48^$TNCE-v*&jimf z&LdJ6b&*u3e`H)FM>-cXS0RZXEeq%JtYL=s7UmiCqNaURSZLvDvuxol5a})6(_x&W z8C!`RC3_FZV4xlmnhuha+RkZ+Y)RM)pP74hZbG&ajRj-s31cgf3v6*n<*8iPat(W8 zn-uzTW`Wj&SgxToJNpshpXgt;7yf3Py$Am9%Vpz&XrXgpAO*8<9jhl>Vra?|&2RAK zLN7EO=Fgp3Pmf))xA-<;iH4eJlq7vi60;fsct4#{`OPoRnQu-(7NosI)hkp`FR5e2 zA4`^MMa-FR*0HRIbQke$%Hj;K_yfc@ClvP(X#)CB5dY1vw(hTFv#2jC;SllvCgg9< zR5sEu@&7FpzgNX$#J_#SpLeq)B%A0!@r}3Y!g{NR|0wZKkGuBR6N>ulEE!XU)SY*2 z{8ha7_UUwMT#~2E(-QqXk)2SNOp<+~9Cx2Ed+!r~!8o2z^}x?dyY3S`7Hg3CPIAA! zV8;8n&6BTE1NMSn75@>D;m&`XyWZ_1+2B3YYRMW?Pe{X$6EHXyzP_!Km;<@@toFPv zxo?|L;tUgeIC_m^@z@cclmJ&HoaprPpH+eDT$*I8yHpA5>k~<_0oS=@!q_RQCCqCu zgK@BCzCbeH(^s#y5qVLXBLZzD0ygTs(lF~HuQq=j`-g~7OPO|iQ;rMdn0dHDjyw8? zRpIN@nUeLucp+@S?LJ$d0bOi*KMVhbc%SW0Bz#?3Awilq*!G_IUybqCLanRal6Uq= zJt=2b4fL){2aA7&glB(yN5h-zk}-1U^=U3p1dC>I+4NnPu9j@HXt3>a2@+?p%^jhQ zmqZ4m#~S0?%-BX@CAhsx)V5tBYz#(nCWG||x3_eT(6Z0oHObg~E5$X*KMsPiHm1$S z{;PD{mlG_X6NzSaqz}T4qSe*StJ|WW2F>S%Fnj@+` zFrqa2g4*?a$=BzJhdaOFsf4im=NF3$#5+Sb1Z-k~M6*)hI zR@wH>fe&p?7!TXwW9e24B8?8e+%Vmuw-o43^ctgwSjbm|WlEiKylv9DCHck3+-NCo zEWL*J>8Bnd)KMa4N9rtzXGHdIUOz1q5pz?<{9P%>W-Q4rTO!A8Bp+NQ+~i|sa!O=~ zw4JYOg!R^7NxenAb)^Iet@Lj67JERkRCtD|KSj0<(3x9DC#I6XiH1E}K3*Rwhxl zIKJi*Y53YIc;)rR*H=j0JO(XrR^rw8yq}$knY&C94;r2vC2R~HAep*k2YX&vv*YVR z@t%e+TtbE?nNB^@`Hytuoso{PSH+9l97nxM$~@~TLN7PZx=u?-bzYX%2wS#e#u*Wx)?@zhEJ=9=puDSxu4Yceytzc&8pGle zPTrR-4UZ3_wR^Cb{{LhJFA>SW1U#M~jmvHNA*&E}U4Hu4iGRFtCi>kfeo@hkG(c&! zgj_rV>G{^_|3;oFhU^UZtd%U2I6d=t;TyPMyk;m(4X|0_EtdYH_oY57Cf7>5p;3!( zt^PjZA6i%5XT{`IiGK~OUGrq}X$+qglV2nZ&Eq9Xdr)(l{Kr3`2#ndhb^lM1Y&31y ziB)c_{DoAfxgnz7{!(&qWH5)mHT${PtmAm*@l5XGpK}FEXnM=7klZ8jhsG%8j){%% zn0SYjm-lq%TuD6^%-sM_@!u%^UF8`(*X~~{ci^?HMxi#BI9DfKko;^&)+Eh~-Vq}E zPpNmV-)~CxU}~!Kf}95*C!{6u30|ONzIFVcmaGqOvT?=*!uTwx{6*3Toh!a|{5y(2 zud2TO;akVQr}(or{r={5luEon{6qcAw~qfd$s=3aFYnzhUnugS&SAXk5q+%5=*Fk=;s{+oO#k4ed!0nlIwTg!S2O=JN@a9=i z86eV6NgH#me$&QFVI1x`Y2(Kd4wW{hu0A?WS4S^;%67QKAM*Dp+pQ9R%U1F-B#tknUYk*-QzS^!%9K@i zhWLj%v!_gdlw5?2Quvgqu~Wx$!&gf_lTldh9$T}@@mg?`DPVfLX**Z3Xku>Te6bJBr2Oq!c%zs=nv0GgE{mmyn{u&Su1&;iFl|F zcnYt*NN<+G=Q$yTmY!7m3XI|4{0v4)je*?h0GYv1qI04$(vmR55hLpRpy?Pb@bl!IU#1H*T!v>uW%t0z5$S z-vc9_kf|cyD78?+T;8k#M^rP7Ue61Q((mrL^ zh%m4&7HlHlh;zBfj|lmDBgBDXa;J8+F3L!2%J_5BmF*UAp*( za_5QPBhiPvJ!N-?NGFA2_eO>=tb&a!0WT5x(BQ}$ z-SIQExa{}$l-=zTeLtsFxQNz19+Q|WafI}#r|d41C<5=i0`~C+ig@qlMt4_B0DYBe_{k%6rN!vnhF>a(l$)&r{4)q~=*sd+}@5#NE5%-651Ub3U@@ z+r&R~KKe}D%@h9{g7Ut*@jCHu(Zt<(5+w8p&^N;SO8oB%C1FkoX7M`l4{0?|=^fLQ zx2N=e5${mj`fi80GQH!}gi`mE-g6@VV$k2G^iCB2mQB+|C5`Y6o2T?1vPB3eO`pl>PQuV2!{uQsUhy!-uA#k*P4bj!rsiG)qirQ?Yvm7;5c&RlrdR|4Az zV}h<0T9=D4Wduyn9m?CBtgKq-+-y8$p?NueCcjvZ-OuEgftaOB0-wp>$biU$Yr3wU z!H~S~GkH#EH9_oW@|>Y+!g!y_a|mt%>Ea~~9i;nY&!;w8-a*GSBml^ZW5*{H|H zFkPb_W8NXZ+OG!)7^Z8`5T0Q=2bI;7VLE<@?QWc_U5JAr_*-rH?ub)+B#x63oZ2$% zTVsD7_HD4gANwrqS7F}``&Y1s9qC$*NyxcQ6OS9Q$7h(ezu03wT5pHrTBJd~2zv>K zeMcN`!@d*tTr-J06P1KPKrKJz^X_Q~k})3E1BRE|AnddqRPJ>K6Q=b}BP!~baP zXJCH<_7&Jq!hR<9r(r(}`(@Z?VBZ_{Iu(CrJp{Upp*h3Ow!X&DoMD$KnsphTWs=K4p(9TczwY#M8ugm$E07 ztx-nZXu@q%wnteMn$N^XU1`F#Q`TEquCn3E@|DrhoROuWITK&4vWu1REu9H>x3Wi- ztyK20vi~UCsq9x}tuP(R#Fu7WFzBbOuQE=yGvSU_R;Fx*vWt~1R(7qj8ryIZJ5$+t z$}UuPud)Y}aju9-m!@+~x^F3aM;UEan{b>dV#0O6*u}6e))jMTYTdBm$|fi~MOlrq z1?UQmDtk~FP05*henZ)2Wi%FN z;-j%R6OJb03`@5z7z|K0P}vw|M=Lu+*&Jn;Dyvg=i?Z95tyb2cY@;%ojWhZCUfEB| z65G3Zrr9_Xj>h6lIcO}-Fq()nELRy##2J>atW;UKvNM&|SM$DqE@S zS!ElP?NIievbKA<`Ria^Sf@_eU}YnejaF8sY=*Lnl`U3wqq617Rw`SqY=g3wlxAy`*fTvM-eF zP!{Xz%HmUV+m;6_>#J<2vcr{4S9XT7`O3~#c8{|Al)a$r6=k0*`>(QCH_e}Q;XY4U zUu85AXX;?AvNM#;QMN?cQe}Tv_Moztm2Fb?rLwP;rSI*gOS5t2T^Wj82$MA^TTy{_zSW#1{= zsjOXhw_ZA07mU;?J4D%u$|fp1TiN-_ZdP`ivL}>1sceg~t;&8@wo6&3Y&U=1tP4hR zlnqmMqOys~&Qf-cvKy4$qU_(wo>um*vJaH~s%($4uKT+A>uy~z&aLbSWfPT6R(7_s z^OfDK>^5ajDSJlQR%IV5+odeBpWFYsSy!5qt!$XGBb2?TtWg=?$4qtj{2YWgC>eq-?vg zFO^|c8{59=)`j~DWxbUZDl1lYy0V$dE>%{i?0#hrDSJWLE6P4s_FrYG2f6ucZC%Kp zvfj!bQ}%?iHaC**;ZvA zD*IX4E@hp1y7}v7U3g}sY`C(Mluc5$K-syE4y3S)5_K=`#{;p%6?V0M_HHNZvE|JU8p~0hbgOr>nzd5S6Wxh+0e(8 zeaX6Lhzz!FvbQ6oQ@2@m`>%yfn(T>dTLDeSALq>A`!sPS;`bZ;or}N1kadPGV9EHy zEu_QeJ7#NU^|6Y%lS}89R?I4$I;$Mu9{8h4lx!;>+T~|CG&b@raIVjb zX&2%zia)4R+3K)bJ@bQiYPHPMQtVL`&I$N4Z)@p_;ahH(U29!2XJs~=Yu(b$z(GN% zw2YZs68<_P&t_|;v{-Fw>cX1xxl%GWY-rz1$(T;KWGRVGEu~YjXZm={CncKzw<#H2 zF=-{kYH@7Xs%$tv!=JQOIrg5-q1$jYGE~kOgJNSk`}~1&o?bo&DZ4AZ%|zS!SB#6n z&zQd1A91mrCGz+m)CT8eq`)T|Rd7sXrnI}`u;qLB!ZUxYANC&%-eo(`*3Utxwy#DqE>+WjdVN3o39hI#fIUUeHy`(o8Ryg9#{qv>PC;a361~C$zUE z-3xoRPzPJ$li)TbrYq*u;@7Z?tqY^}h8By)Q;8cZw#)Ap4GYBmUlfgLu@U{JFFskU z1#&X5XC5+b(N2Wh6pb!ZG{aal!&WlaTDmj9k8Gjg_Wr%n&8;b|DgWce`y&mPZA-T= z_H4NQZ0Syc+mwzjQ#!*~I>RE#Sb%ImLM{L%%6nTSoKc+4_{>0DDfm54T%GqzaWW$% zPU_dK8k4FLr$omY>2atgs>YcT3O`uh&D*NrH1Qc1<69)G^8u+&yFuffc9CKy{p(m` zN>!^V$>WS9{(?B_{JzEwU`LaWTFtg_%4a|3Bn$ zuEuFxjPp8S5q!U!I1)~5*PEUE*5KEa%D5JRjxiT)s{h+XYQxcq%8T&~xm#0lKLXFFv+s_WvtvUy=Z%$nJL~V=$N9&N-JR6M*;qi#i=h+TCI%{cf=irCD^ZZ6VIf&n1H_heU)D7e2#5Q+pD*hL3{3eXszU*Tr zbg%@beHkYwFuGe)@os`=)ag7R&B@u&(dib!cYa@|H^w%mG$dCgv zrsCcKKgMn9+pUjadwIDx@iNX#7Qt>!#rp&NOuP)_wqsqCx#?t7QKdo|h zRo{xTCrT3|d-gDv{ORSTHGOk)mqnafL;99gmrtviU(VE+Xf)D~&cN2UtbFRc({qj| zL|;IdGFE6{vth;)a!eMDoEz}xLEoD41vNRd=g`dvq7jypu2qL@JIciEPm80RXk;1g zDyP83Em3YN{PFPgh(=iV%>7~QKgo%YhqtBCNHMa-n&y@q7Y}PS8kxr8VcWQ)2-)I+ zKR>BBjz(&LyD$*8l(=|epwWnX(k{EM{k0}%{&;xWMI#U3mu2S`i;IV+Pc*_21Ix9g z?{jE;y8Q7_{YN7kf!TYwrN_m?8}Vp_*CVEt_u^g1U^pJC<7k8vPEmQXwTX*|DMTa7 z@k{AhqxOF>KAtQI!zrw8JehIvw3RS!eh$ClzIE~Ow39IY{IrdWhx#%a;aSU8S$N>2 zA@T9-C1JkqkNQELxV4Xqrvqp-@(_MmKcgaV{3kx1juOV7pAK>HP-{mcyqd9o_Nz@> z93M|-36qGt@Y=$yQ(QdkS<%R9{4zg_in4x*j|XqW5T+jS90(V;E^+ZN1@s>@Eqhzh z+nrX$$FsMDS%wq7(e`^>1;PC1*FF-4xnhu)XH9CN-SH*`X*J-NdFHlHTs+yJ-g(iX z&)~uF`Po;(_|J>%xOn!HFg(jx&%1_yczAp~`%9Sj@avw3`^Ck>9_r<%-Ht@`62|C1 zzYdTvEAZ=`vuyO*=H`>GxB@f;Kv&w+9A^pG%aes6kV*J<(b^o)y#A3i%y z>D0>V8tl!MEiL8cc^}6m%m=q@B}W>7e&mLkZb^=kzgU77A2#N@Ea{=-SxY)7`N)zs zN~C&0yC^v*Vgj{QGS-rGC9^H*q=X*_aLZKkgeBdSY`3Jn5`3^C+kQ&$X^7q2auvi8 zd@d3SbCxA3h{v>goh8XaO3TV-&zoh05;e@taq-+AAhXM7Ppew!PYYx&%s~56&nX@| z$UWv+ne6xp^;nQl^9Kpf;vk_m76R>QHePpvgqlrAo(&>b8zK0J%Z%o!ZG`mC%{8Gs zf-fRvbVZGA!r=2g*$nBspsci})R2R*i$-`Y=62V;TfR4%ghy*_jY$}%ZuXrt9};B>Mlw1f$y)d#*_TG>C$p6f{+ zZlxqlAg#V4m5pDf_1NK!ADAmF4xDLLO2P!vf@1cib@|IrJnu;@u~HHykQN&t8u6FQ zTpgH}SyJDOgQ9`7p#FSmZC`uxg`U(_o0fzLq{W7eMzZnCa$Pfe|5oNojRPmmDoqI! zNNXT`y*gyMJSl!w!cD>i(qiZL`o^Y1pUW_#9frn$S~dw2NDG%4Ut05@-0_(wb)}V( zFoCpqI+z?X+Q$+WZ!lMCIkHj`CXg1-2CrNPT=v)np47)yO2P!v;%OC)U?3ygjLIu6 zGNUFQW>URllQ4m_a8miwdg_jT3p}aAt(1fbq%~Bec&(8>|IpxX%@rTOnQ5gYOdzdc zBITZ6?`(SgT2JauDZIUNdYo#PiAgz3nqE=+NKIvP2fhV=n zN=cYNS|dctt;2%{o_v`n^|h6fFoCp2ij-T2Im7qr;Ysl`Ms5-&kk%+ruOHrY$)`o0 z)D$ZvVFGCth?HBdug<@JUr*{rDT(#U`Cd0TxX+|k}!d^jua{OdDh{O zVHfxDq*AQhQt0uK$lGRb{0lOdze}M9S@lkH7ZId{64{R!YJI(&B>jY3QtrM1RyTFqgZ>1zmAgu`^#dDck>W?+}ve2!=rB+J9 z1kySYVZF4T`KW5KCv~@#k}!d^P7*1m#q(=!uUdSo>87>HN=cYNS|Tu`DSewz6 zdfrM&7=*(!S4-$laQaqzW4}{CysPJd7fr-{lO6IopIIq}2}(^2NVQvaXRRld$qtK+ zVG^7}a5SxYVO34#ru|D> z6861;Y+AZ}j__tmS61GVua%u#R$fy&ZAN)n%aQzEu&L$KE33=r%x)$YH?h*`HRaXK zhO!w}n{+J}T66R}!QDvRa{f+mv^OU+RF}>vtDG&3GkNN~>CW8BvWj`LCs)s#Q&Ta! zeDaLaxs$7=&Ejoh6F%r*b1EG9os9U<*(R4Ss6vdE+1ki+CQlx7d?EO(^6F7D%BRf) zK!2K7T~V`eGTLO?%*oR#D`!@eJ2~^_oK-QWET`!j33THexvTm^AzO^p?OQFzr-53G z%I%0PMx}vTjLPjuZfiO%#u*>F#mK{5rRB)uL$?^Yo*^yf*bCKSWNyLS^Qpx+;{vxB zwOgz|6m?wS7Nd4E;x?Y1ihn5k@lw-flvd2i$!(^u|6Xc;Ue2U9__{b%?sKT|Gc10 zalrqY;-43^r-T_DSsk6{UTMSB4Q!ss+slM~KJOnZnNiZ@$qQ!B&d<%w?Vmd!cVOi>DPbofV?5u zy7eENJ8px_`AmcM7R`!>u)9=e$PJS5oL-sB?;(sm0o0B(i zuXQ;czAfL$9ND*eZuPXBTt2CljW=FXa6iOl&baXwEg%1FI6j+|?Q8fyW5c*CAK?;l z@E!h6B^)($QcY#$thtkB&s{io$e>9xDrc8Znq4uix^fayoiwXrsu|Bts+@X;?`Q#n z9#=lAymW5)r1|{^^`FFBlZt7Rs>|nA&a0kQ-WLu=|2_WP+sMpFUfrcPp8R&z9VcvW zczn`cpY=4e$n#NvLI+liu!XaO6cS zIQtLk+dsGOfWb^yMg_Uz_PRbiH2{BHZHope7+?Pp)wurpWLA}=oJtERqa+~0o zLoQQq8J_*d-S`lV&$yzXgRr0A9PdoV?`Y>ZxQd)(oUu4A!tarAb9*vz$8OUn*)Ln; z&+Pfol^f@o+h>Rd;CC!ij3B-mOy8`4HKWrJTZJ>rDM!q6@by6@!f>TrSaop*;qOq{ zPsJ~%J{|<_hA)83TxXiZQ-$~{AUj9W8IRSP%bjebQt6a|&vRzuh#?m`3|WbzS>RJa zN`+=)hPfegeKI`}j@tm7$6mS<5O+0F_R{O`^hN&qI{oq5gD!4^&=Vt4rWy%92Pw@$ z-IXFQY{dA~IPLCW$P~l>bO}8Qd8tC4SyQK@Of`^;XUzLFhj|@x+Ckpv8$+?lyaF3ih2 zcOXHm!2ktgtXgZW)fQi^tyZzNsak4@P{cHLY)KY1!PkVbcabyiwmauWxEv zFT;DPged!{5HF2~Tw?JD#INi=Fd!18xG%0136CqQ+99Otx=NJM-FR_>tzvFK#o&kl)2CAiA6R+aYiYD#q<{kEw2Royo_#FD!2iX~Uvt6Zv4ETQZEK(yO^mRM5A z-SRoHB+h*jbiM9dkBKEExTWGou{8Bq*zJ5mERAye_KMnyWumt8<9@fRQq;a&?)~GU z_Sj>7_sl(__SfL*);=bFE$)VUMco^Z6?gY_iaPD;TRtF`Ej_Drcl95MWhdkAc~~s_ zb-U-T63g4pD$QlSE0&k)ZtoS#OL3q0AF({>9(YMCFXSG-SuFRs6}e+Vx`WS(6<+uE z17Zc;gKzb_N3Ins;@nRf#flQ#DLv1LQy%!SIQ7hz#A$!>vC`b<)``;zD|N14ds)#$Y{E#T>E_zg)8Rxc4i!+P4{A1$Gm&5(wL2>4etZUq|uBm0qnq;z7I5SgY+1UwaJUfz0=MFj(*~#ogdOQTb zF_W9gPE9%!>FcL*@v+%SPpnBZlh0)*_X)@3l^!3T8g-CS-V#cWjk#e)r*paVK?@qm zPB!n)9I*GJQxntaT*lt-&1KvhAT}d`jm%Dt<}wqRNjJCbjB|4)H)SzUU}WjuW+p}_ zroFd*Y~bGD#!ly^@|n@RGdYzW9nH+lgky4<^w`woxLceFlZG)j<+6E~`H9&{McxQ2 zH#?cnPGp>YnY=SPJ?revr1P`6jGK)?*q@$p(wUjbtYyF#bE7N00K7Re!DMF26`?o9 z^yv7+tg9g2sF|5eG%-Z9MCO8sbxkobGK~?#D5T_983{qHW?XfYpz%!lMpvFv%XAyq z+_SZ&g9aQV^b5l5vZGygZa#iW8<9c#PqmSoOB+lFEo{n?fu=Uj*h;z z)|vG9OuD%-iiU~_QgA%^2=9$EGP^efaK+SnN1Vf&4MdObPvft-F*YKeZaeLwtq+qRHv4QQkB-PMO_RuBWNe*F5}FKB@*3sZFC8I7Gg14(=bwNYTh)O&q+;8??q2P>Gq!5I$5M(mDmWS z;!@@I7P;bSOr}T29gM)8Sy+sgW@jXe!Ma}u+zb`+X&Z z%HTjzgrdBV6VDhm*h0}8V*Hya(1x92jogxm98kJ-6lc#|43EXqla@_=+xk*hUDem! zYR1HR*5a$?pp@criZ+;@Tm#xOoy$&S^I1;IeEDhXWnkHTlTK!=dHwpP&7AvS5S&5V zu}Qqq=%1S!o&9PJAtJq-kvCNlqI%BaVnq;krl!5~0Wb9;$!|*M#%5&UX7;DoH#Lu> z^P~HNd`2R%&z(+l#^q-y8abZ97&1!W(>FMnwvEo_Zp=tPFf)b4`C=S98lxmS0TuU( zae8)S9K*}d%*=~3lfjZsz8H?3+WN)j<#QSfIq|V9ZDjoPerIoXGChv8SdQ_iwTDTI zqx2$Sh#Z?T;_5iis*? zxMYzE7}nPab3wTlQj9_h5wEkJ)eo-{#ED%C+ov$Gjeh@BE{`QSRAP3T{()w9*(^KOIn_3#zyR5{bI7r7;-9QV7#}D&d5Z70Tc+83PXvrKz^{?@i z{mm*Kub>dj9LNaP(=D3@<5CVGXVNoR^DY6gkZeO#3yCa*Tv%oybPDa{$|zIB6f|r~ zt*~NJ6wBYuO*hZBw$|SEw%+aSU0dzQ&Qw;QotnHOYNSY8C{R7Y=4vv*K2fY<7pxPO zFoMHEtv^D8N7Li!9Cj(NWnu?3T;IZ&F}SR4^)oU}@r9MBWNrbXVx5sR*X~Wbh(_U7 zL=l`BnNpb#tq$F-ec0pJ*4^IM>J~hp2R6Sb@^P#MjFhF}L{y9$>E+PL%*YZuH;nD& zs-*A%CZ{Aw?F{BJ`?%j?5xBeOa8D4sPKF8x7X~Kdbs{Z@miD&xZOQE&SGBI$xW+Gl z>6=uyEVhTIE5z8;^vo|;BAc+(61fRVERjucawVEh&&=F3R|?0Z;G9m5P2+JWRv1X3-w{+qQRfHammcl59-6DW=+5w{Pv<-re8c z-nwPomZrw0=9YEqH*DOrIoa0Uk-~;-*HzoQdwTo&uO1j2!ij_u+R3=b5@4i7p*fI* zF%CJCcXw-l>Z6-*Q9g%rY4)SW6|co#0IlBa3?*!&oMVm*v$5GX=387Ll7gZ z4;I6=%>q^+j2zKUB9KbSc4BG_#>X?Q)hZY!7u#|ys%>PYl*J+!DvOI$pe!y@v9egq z;$<;SIc)lEaSciV)?!<@B@)r9y>T%u*^3g{dc6p`#p))yxvRamqb=FfZd*ygMiQg^ z-X;>;LW(vJgAgl0=OmhkiyN;|9-I>LEYdbyV#U-63yH;hMqOntZh>N0dN?r>S3@pN z;b!4xShN^M<6|3zV=&^`D%K>h5Ekm^jA-J!HV;Oj_CVsM0~;An-;ik@!N8K|)f53| zG>@)LhdFe#H)hexWF*IxnaNSe7R!b{XfAz|3kjqfb0QOJus7wHZTf1HnS0ROi{@4{ z_oBH6&An*uNqhF9({c~mMO1sx7Exd=b9~&H$?W4HIkoc~fT4dkU20RRzo#$Rvwdr; zwh?B;y*;(HE!oxGx}|Y?%bJc}HRv{xJ>A>-Q>k7gx-lHto9gfG>fDBu`H0BwWKR;S znyqVaSSvu5yBhd)AyP}*m+R(j?c29^_V>8aW4`#F*51Cpe$19!gb4O}Tf4R=Q+@q? z{Wg~|FB;YhSmRV9dCE~KfW3_zC^+%+O08(|2;5k8M${oeS#f)_IUK~05KI{*2qtn0 zhdEss)~d5NW6qVG9LpSlp~jLVZ!pu4IL?jf@mU#-kv*2Rm6|gicQPRmvRrCLqUqT@ z^5Jfy;zHN)#_sOkwtkAqR~P>BhYXWDs*30`+{m%$*s;vsG-mlhsClGJ^5ff?jJ;q*-;HM@tJYbui&F^>2(wT$vx|8YHwW7!*1zM~+5*d}sYHn1d z8VVIgk=rkYQGEL_k@!vUNk&dMGir`CD4AB?+ej)=y+Z`&E5Z~+L6-myhY%(k42iP%WiaDP=vAaup zUAA>z)sakfb+ty<4tba7(Y@we5>(ItudzH9;?448I%(1e(A&%j3fHS%7Xe~D+_zgM%#<_MG=W?-Vt#Dp+#Z%>NO6*kt=o6 zc$R1iBhrF7mW~;yov6HxU<&4FkWPZh66E67sz~N2I-lJrh;=gTNy>OqD(xOEji+6@ z#0yMc^q?v-7gJG2OZgNRo@Bx!H$3btto%K2`E*bSpVQGo>hEtjQM^bD-wdGumdDga zVTG({A*7;t8fttJuV5hqb~-9k)6j~`BfJ6=MbBf>BE%oft#2dKM>N#CMa0I)z(4Bs zri(R0My`=un#kDNaS>uTDo`69n;p?Q3d=Ou^^D?-DGdOhJF_M60zHqo_`wcF2s42( zOaMbp?ftqEz%XKn$=aEk&0}>So`m~ckeBeLV!Ulqs}2R|(tH+*F2-0f4vH~QIRALL z?2oKV1C8a%BE(ghMTnM*jgFPeesea)U)2^I&zeaXD>9cx40D!3EO+kV27RhyZ^j9< zhbR>HSi4leC=~f1vTmlaNTU-|H~QrgMT!e`#j!YPh|t_9g4s#Tg51TfSoX3rlbL;Z zX4P}vx)AQvq)ca9KS7t<{zQEPEZrN(3M`q_hm>Pa43N|p~XOKIn% zn!}F5#B?de@+g<@=vJ(>JPAtHsgjhXw9?ItIxr)}brg8H%-HOx+g5na*ENdfDHgL9 zXq!}Fw9qp+MbJYJ^^}P3ujpclqD~?gNrRr#w=`D-J#-qg2!6y7%_1p$=Qc~gJ=vOw zSz|1cQ_T8f(Nqy@lO?1%sag-8S`Fl2MnOi!vHa;-GARYw|Ey9eDGHV##89!;5u4!T zvI!ldE>;qgpqP$@`1760E|v?CPdbMp?KZ?wv4$H;P`u@al0+XmFIIeCs*{$3Onp+~ zwkb|JuhL9MNGzql)HceM?Mlqa^WZ92n`oq?w0RILDfzM_B(7L!cl=u zk_ZIayg^ zVA6s73!vhZ9FM`c>=(xkKZ%zvkO=4QO3pyzo?HfD!4}{qDDMKOI8ZlIx*R8A)+4Y( z^%GS!A*9GkiNlJKRtP<^BI2-0B^s-4A;J=~w1Rn2Pl}P!iYUn!R<&sEqctrS*VnMA zXwjH4dKQCRqMDV+YE*LwWn3zQo+hBqK{w*$b2Cmnufxgb4LAY42?w6jI1xRHlhK(* z>=i3CeJhVj^XRla0gc2sI_)=2c$*5$^uEyvC#og6v1ZH|mpW1t-Q+qtG*p(BE{tXd z@I`X7%3O?Yq$0c78s!a+M+4j$v|`)^@rrSW_q3*OOlQZ_SVxa5akK)uMTpWoH#SD) zJP6V4z(w$k1Wx|D66=~aZPwqFm=HpYza+#57AM5O2NGiK7ZYMfRhhV|t4!>AUzxc4 z?lSSNe?a)_Wuoe*W#Y;DaK4_Q7+#0WVzV?qjE8_xI)}} zUWIreS0TRp{R;7pA6JNFs}_ixKfOo{JhVt0`q?7UT2?7Wu39Xf{Z6&G{Hbd3%9pA| zFXwg?RSh3Ni5aE5utLTp_M~WQAz_$qMmY&ne=^ z51b-iI`dTVmOnmCeC$t76YD;Ant1R#r-}ERy;7XId8Js>u~IxZwo)wogEPdHkDejk z^2`~c?21+5@oQI!2ku%W#*eKMU;5Wo;!ydS;?axF6w_PI6p!W46c7I3OfmNAv&Bct zgy;~L!l@r>PxOd|;+3LPTqPPL^h&WnTqrIP8F9JTAg++Gtk^Ct6N92lq{Mo04t}e} zO0hzei3(9J>hK#EN&Lpesra2CHj7sLQu04T>bFzu5W`{%;NwMpH;CfD>qYRF6gWZA)|sn6X%GR>-Sn=e!InW`u7@9 z=yxsZb|~U^jo@!k{#01qtN+)E=-&XeYC!ahtKroDUePCd@#Ft)`|E-3xxekuG5_x> z=%o2|LHD-7d4DFZ6WYt)l_meKfL@pOGqmIUOVOGxMN3hB+<%jL16tGuv>^Uk;COcl zerxfguYT(8V&VN=B>cZi&_>PgeDP}hUL`KT@0Id*jyMl(bPZbR8idZ1|5a$UyeI5D zajyKS6jA>h#OdNJai%yMzf}>xGtknberF@yD_|e+>4MPj6bWg7t>JG4Y;UdnEfqCl ziTu?7%HMKW75delUxTRf{1yxMM|-vz^{`oN5*y*C@N0ubN&&(!f0dr!LLFWJzfAus zV9ivRenS3Cobk(H@BF`nq^+mMu@9VuU-6(*w9LVyXmRh?*DOUJ{ne2hqmP1{*y#6- zo7m`Ae%aW_XR>r`+#?kxI_8~$p6FlU;k(#pjy3t%m$jStxEE9D_~LKIF^DIz!mN{= z>?;j)vI1{su^6%ME6^A(&ohgfSm9MCi&XGw68}3N?AsbKCq0Q%>1L(W`!tN*_l!Tx zZj$-lPf*}+vcdNpf^d%%l#q?%#TZ9Or_9=2@56A zpZoBBf+OM+3kGC9?hyX?gqe7I-$(w-zr);6D`^`4ay|82;-Y{;d%0fwEvXfGQ!^GU z{4YY%&jiOlh#ucUbV{?NtDnq`e&Ad|z0aGQMQZab`!DmPdi3G_5EM@U@IxRGaNnZ= z>cM>PBhY3ShU;GLto%1?HpSLff@?8x>nlOLVs!sMwq|22vs}?K7T0z?QEC)Iid^A~ z!}6GWujYo(wb=c&5{FeP(cdhh$1IIUEfR)=Eu|N;U>JiOy?7Wxj$XrzLMy)1Un+y1 zMRczs{$`^u;u9BzwjHBXCq{@dRTGCDR-RI}fA#h;_AXr8!B-o&@B-%yxH0{|VOQN+ zbx+Ch%JoQz03IhS6;(i98X;a}8X@*9f{qUx06*ibm!P7BF+5ulF#;f+0_PGmH)gbG z?1De1!r~~PKA;|dD1(v3q)(tL8M>`B@CTkEQWm2IiS)Dow^To z*pUYT3vm^5NU%^6--%0~VwIfgq~#EOhO=mXzVn^NLKRbo0tXxmWf(d;TMRjTuC`c; zlWPa)&7(e9QLOl}Cp8Om7yR@^ARE0Y7;;!rYAx4ViqP2zo1}4iAu12!8AqM zaS**&GY;YxZ^gkBp;N$~+Ks|J*_tS=5e0K9O=ZKWiXVWFN^?@R9zKyw4Ug<=3@}n= zp*|zlMn&mNq+-O>eyED25sm8nWrX3{*ED@Gk>!yXp+Z?`WSa1>g|aN5G9lY~GS4Lx zP^ws4SL&(s=%*fk^KAHL_bK_`JR5F4aOKLR`17q$q0*jj#nZdRA8rNGZ=MaudraI; zPS*vWeg4g};rx7dv?cq^v*G-LOZeGvDJ}b25!+?@!E^h@67$BD0CRdE6wjMM__e+0 zMQ7mWO9MSCW>S_G9LukZ5y!BLff1E|%ooTb_U$j4#BW|Ej7^xR z3G~9B0*#VNV13(%@|!pDg=e~60Yz+|c%uWNJ=xc_>h|n;6Rp)W4=k{`;*IgQLvM_) z{dprIO5}}>D3Md(oxXl0HH5gU63tp@zsH-T0BaHZG~O2}YpXR6-sEhSusv^O4stag z-qnm3X#X#N(YNQ=sBKgpSfEjPWBi)yjqx=qZ-nVjB6AA#A>MSM#rCMk0<4Nd?_u_*y37@g5~yN!DvRx#^OY@{YbV0_9+r4uvhKF34L|m8(V~l0(l3rRELjk ziOpGL_uD1WpDxiyF;DKpCOT0lGxce^-+X|pIs2OraPftW>Jz8tv~T=JSPVvZ3>qMT z&!)sFUHms#EcKXgv3TOm2e`Bq^XKlqYcl}%DtuH!(qDX3M%6b_2olnR3eOB7h+#j{ zQ{WRkxRQpArQp#eH3zfx1Dj-4^saRPo zX7REZ<@Sucf-*EH1z0QA0LJ(|ub37fgb}q`Btcl_g%iY9Z)7s76(?IFo3PXpxd}=v zkxg)NB{I4i*5XJ381xdEIw`e|GM$l3#E&H6&?8N19CEaIjj-zl_=vIMND-j!K4NH_ zlnZiv?`rnKeQR`{2zRSAikur8OWBK3JQKYio1K^*&+wz5c$xf^JE@E0OTXvbUn3sO zu!;0Us$d|kJTQl&C~k=j!~ryX0!W=Ki9847M)}UhxZu#_))(cS(Yg_#(?4!h#2Fwr zlBaPZ%H%uT6Bi%DeuQwXtimUMLuZRz-onT+IffAnh%k&?Kz3o|g3=757ZYSminxO6 zKH98aMAS_1ZKTE2GlXAAbb;)HXW%_m7sM<-6sJeg z$bR!gvT^}DQYtDYN)}-WL@IMQvk3b_9tvq|AuWy9&hW8VDd@QBiK>)Xt&%U4a1}_s zUjon9H#Kh>^{j+o;G0R~6^SMybig=-5PB#e79(J~f;olTbP!`QJv#2R4Z1IO3}vM; z-0wogVYrVDMq{LQ^|uwvr>8i=;Lc=!tk50F?Lgm9TM?AOfuaaSc_Ak)#Y&B%uFfo` z%q`8%NY?%CQ?!WElVio`@x2bkaK>l$XZPketaHY*`TTe$GdY$`d-}Xc9hk}$qneXc zQI3Ga@1r%m#ax_z< zDS}Eo0cH_=%t7;O9+(RzHgIfpj*sBW?CJxdq0h1FrK$iihtKK9Qj`zz$C(bBufg&S zAXP>9aiYe}QFsv&@)M$zvZJwV7v&fTg_tdYPkdChR0$U{xx_>X2gp4*7NRf$_q zQGx>0V9!BTtt~bpVi4`4sGduXkgZE0o?RCwLS#D9J;v&1ZBsGMBtkr6o1CJ2ZF1t- zDwaFr<1;UwHu{+^M|AM31feGrYM6+eBQS&Q4$l}YAhNUgu< zJ4q#nft&qAsprNSnFR*{0OzNf95%GGGkJDr-ssWsDGI_1@;7D-aQSgeFMb79I*~#qQsT@ACZeFj)?}M7~ICUqNOXKLe z290DVoA+n1u&wX;wa0W0MK||3s1hnU17^IS@l2ZEbk!hMue|}eW{|b_S$qvcF5P<| zS$us%r^Q>kxBzGG$Fn23G*pc>H$g?$cm|H9GXpik8H(#U){BeHPI_WN2PL=2Q0CEz zY45F%g9$3W8#|qw%4bINXg%rCQG6pl9D|AH*wo~>D^+|d;io#X7@yPG&i+-CO5hpDx_H5Ju;geA0yh0qq}dM z!8aE+dLq}Z-EIG-My~h7?95KKH18hBK>KGhyKih-*R-2U99a-iTDcbZV(z$@&1c7F z=9mYqY;(*7AK;o}79wr;eBw!+_|SdKJYsB8elT1e6rVqA%`qox#5l)H=xL!Dde0MX z%<{$jU`LM$H*r`zzc`v#++ZYW;QM|X~S(t{s&gPEJ4bIcRg zqOlD=Z$yOcyP3RP$55N|b1WUR!9Q>0Gv8Huj_b>}i#o@=@chagv%vE_bIk%4%*L^f zKF4fei->3U=9mlb$+9_S#k7>US5o%?tb3Yt9*p}!Y~hURJQ$@1Pxs>J>>O)SgrMe_ zBct0!R&&fw{IT}=!GAvrt) zF)v2L5lm&)HO-Scvyz&Jl{XIt=;6jT$MvS|kcY3iW(ZF(@Y^9X>3OhmDZhtfJ{&}T z=K2t*kD>WcQ}&xrbIr`G|EqFy%nsjy=Wgei2M6ZKtcJ|V4@P=8oM&690r|}{?zGV~ za-3sb^KdhNHk=`wITlNLHoxE5k5}-iS6$8hkUzlCJQB~`%SP)kMKsrP!K2HLec!`8 zvDj%cHP4Ko*h_3n-%Jws_sOM_|{W@c+C}+LYytswRS9r=i%}AzrHSk|6Ib{X}_vYtR2gY%`4u-ZlF}3fqOsPs7Tb4RLPIP|1!_lUn(xI7Y*cpxu_DKL5Ymt!$H~$oygvd{hx+*tXpKq@e&JM&%v#POTg77&iwPtJyp$P&wukXD>Ib?%ReZ@ zPXNCWPK=iNHUa;;1@tQh%o_nl#hRhUhPAo$U?!a#-QRFU!bl3mm3REM)H;PkE*^&S0yF062+xhpYUDrJEr%#L>1^i`~vwcOv+UcO@3*CGAx2=jIi^VW}5Vp*NR z3HXPWi89ew|17|bo+!f;eZwoN`4CZ7!Dqf_!LNaT2HYaCONXk(ZXK!;cU#zpEbP;Z z5sZ{WpmB%fuons20&*~E*ebsmD+jGT`Yk8Lr2*>!dR}>$e7y2N*$)9tEP>Dbmuh*u z0%0W&hLk)QsuCZ;e+B!P4poUyGwH8I9$zXh5BXk~mrEYYv^$N*)X; zc`&5pph->Fi9NJ`NV z@Og*~qHmBI0z)JvLW8L!!jO^(L#o9n7+Z{jHLY!2i*Jp!auIZGcI-3hio}T%LX?Zv zy?7h&+Q!DWC&VEI@eU>^!tw-%6aLHFp|cs6CpeVwU*16kRlYpIVTAwkcKEEM@`N!O zN6-H3f2$tBn-}%GJi+diAzl?SF1)Hl1I#Qh8cSXaEo8F-pqDZ@ zJ2j+2Le_c)8Z@`%2}*$1y{-2`lX(Y}No#tT zEnA%SR;O{p*0%Qkt;vqw)}}4%8n>)#YT2?TnQX`& z=*_J{Tnoo5j@|)8jI|2!&7?$wO^W7^^sZ_X;s!Wgh3L%!=SS@duMoZ0bO><^9IrTf zw;{EC&aZ&VEf!-T|^M}_f zyf}J~Ao`ITU`NLlUYz{$Xb{JM^XiL-9@UTRSwfF3gz7L!iH6Dr;NpB_S)!in<`L`>2i{M4+3+YV)=di{rMDO>3 z^9eR6T!rZU6gXACt?=ULtpa~%0q4>?6@S0eflaQ;N&#nBrBz0U&YER0Eb+5Tt* zue9`BD?DKnJR}JX=Ca6)KsXIFPBwQC4dBZXgPB6_-dQbX7Dr)*5Q ziD441u8C81nhF!sKhU=onVg~F3oJa@zCF2BC1PZPYAc2Zy07i)O%0^BI(k7*=EcZ_ zH*(wd?jA|=|DZex(VrX`OgZhz-oDJ|hd+(KXoLoxG;K zueY;ns{`V_-CeyYr*EJmHPF?&)#>UTN)2=;+fyA_TTd^_1urq+_HC)2q$RP`fV+lV615uG(btpg>a{Yh)8OvD_T*4kUoTcB z6d(15h^Z!>(8zq5j@R;9fn?=UTlxowtqzgccffx_Ts@o`xW>UJN4f@NK2Apx%&pe( zWjcNcg?9Qno$ln|kkh^`*}GL$6={@f9Ef@dTH(lAg@~o@5TPP~AX^OE1tS;e$bnSn zKx%NCxCrncNY2{(dbW1AfwlHjKPBLF^!4@)Imo=DJLPmHhmzg0Es)AWO9iRgP|-H? zMJDrPuhW~{(Y2MuWBX#VN*y^om>P6?Q$suZ2DV$8i*+Q_vptE5><|q)S(O{p)jJ42 zx>Fq}`M@<+Zq+V^N(;qvdXoM9pz;b$rN*1N#Ijj0ag)o|sLTjCUh0WScBW*LBD~g1 zY+KjhP~X5comkXWU!w{M^ak~~ji!Gc9$b@lFm z8R?Mb?4LnQhz=;&_O9Lz2R0^!b+kqGgeP2h=WuU3kz|1xSLVj;NTMAg$|Ngyqo^II z#C|DlCaZAcx_bJ%yV|>kAjrP9t7N-6A(L9jW$iaV9|A zPr&fEtD|SI%Yp6<4MTHP719DQMHy4{47T?tVfMPEjF}3(f)QZ92znp|im39cY`aHxZdCM_$oM%Usa)iIFl9Fjs{EczB-Y*#P)NLYhG zS>gq-UMLb85KQbK4M9)xD&95As$ixIm}zH!C#;jqm+hOB(J}cbr#iZZq}DLeLdoeh zlu@^=JOUTVQuXij3mpBJkIq19M;D~Wj)U2tKl4R{{k~4AaU@x(Now)3hx>Pch3HJ7 z_6A^A+pbEr!>q!{&}lObOw>j!HlDNP8IR@kIF(enFtI;f$W*nS}b;}-91v`DF-*(QJP+2);}s)<8jEKsas)}Hy8DtHvZ;`DH3WUz0zw_{LTsBupX z;dZCCCfl!Z*b~tb(P*2>I?WglGStpdHm#u(Oy zQr#GTxEgB;ce=&wOr^jujq|^PHaZSD3X?q$80bm$wCTQ{S)XB(wNbe-+U*~f)O-4e z24&AmBIsINA{{U=Luhc44lNroV0T@N!PJmEFd!QpW6=fpV$JwpnJLbe{smYD+g;DiE0E_Sv2gbw>>NmLl~k!F-vELT&~VC$$=FlL zSav9kP55G^cuc}FUlbafOh_eX!g61%<(Z1b=n8-IkeazOW`QrJze|pReu@Yo1~WKa zol8znk7q~Km&hrxDmmHi8XM0H?w`$%P2DspCG%w@NeEgyc5{&QHjd5E?KB__Bg?#z z$#%|E9CpU4p%SCqivi6TNJ_&`0WiA48{Lh0)i8QJIj~^t0&lFb(l&OXH`bVLX(5<) zkvDcY>GXH)N_7v~#Fc?)bd#8&Q%#t7u{XAFP>vl4ukymlki#X5A*q{;ulB}kd6@a& zpd8r{tHz7f-^VFsU*GmFHSHwAk`RJyKXU5L)fwU}_2O`;!bH@1Bf2nWd6iC4=Z)y> zPHvU`m^0L;M_{%T^1B?Y!C zQdr@|&?_raJ2>7V!YN(^&J((lSek(Cl1oeM@riY+7Yk-#7nW{xk1i|p`@lhe(bdmx zeY?{+jPWkVRD`1o0Gu^7IEdAO-Y%F$PEHsHl;wZc#OrsoSdOw1(`N1 zY{}uyj}U`(w_KK;F?uan=49JoUpFj0>ZVI7F>#jqab#nV)xz2(LaiTR8}(e8RZ4~k z%lrr&<;y|%^OggdX1I5IF9)ZzQ;fp8ADEL-9T;`9$r4=Vg1h>6th4ZPAAAGgHTAPB zqP(Wl`|ykszswi+TCizz3rP>5dkiF($N|E>IA`SWJn~hU(`; zM2?baBP=tPpmMcKK>islBgXEjba%m|lrAh{6DEAcf_t=Jyaoe(G%qz) zq`@PeG0_qaW$amn3$Yw&oID<)qda?Mg7m4#ZsP#l!-U z%GQYd72a4%2Rt!X)rbe=LMy49?!}XRT<;M233SWoZu)vL%th5&{XWBsjrxY^9Z2=V zs+t1H-j;M%c`@b23fAD&6ad{AhRsIZ&h#R7X=~@I5W8E_JIjlv%mQtaw8xA;+Z#WS z+-VtNH%WvBFM{kQJ22r<#)W-0anAALsPW4H7rWKig&3>77;4ypo(MxAV=m71BlPrR zX#h(a==V6pZ%<*Fpu?7ZjUSnVAZKv6UrsrJW_04bC^Rghphwc31IIXI@0GEbsx-EG zUKNWtkm7QbMLa(i5i-PdQcjDR^#!qr-Kiv2_BkE+1@N#KICWDdH$0Qc^`sAECuS$) zl$|7A9ZQ0idFucM-?qLl^x|syV(qlk_B0py5L){6;N4c##ol;q0LZ09U8A<5)@r$~ z^&-P;4RX|h;YkqRXu&03d_VC)2MdmUJ5jwx>l(et(zLT34q)NRWZ&e&P#Z0tMrsT% z>OiSMvlm~s1WY}!AJ)~2@l=mo#x{1M#f#cM+}7PSxD966_6kM^*Lm@nH+I)J-f=OP zBJ=N|7BLAQa=M!3aGJHc-kVac(Qpw=E=)iOCRMpiwa(h54Zc)ze@#xU{GAcEiwV z8KX^cX=I8fInk%Y7BdB9Dr?4Ayvrg}HCw8eN5;3vodZ&>B30OD%z-{8q^PHd*{sB!0V%?~IJ^u<=_Xpr#v)w`U2sFOD8B zrDjQt!n{H!mGd;TSQ>K1U}m9X$w17NfST>nHJRmv$1J}Y~3#>qoAmG!G3!4A2W zjR`y!6e{aqhvSX?!#mk7SKyYL;tr@_TbzscSl_J$bQzL$_hF@nsfacKwC;Y?1=dC( zoX$Q8<+K}V-IXDm=dev(kJJ%c6>a#3!h@aXK$Ux#>OVJyvq7%mH;c5iZdE1%L7M?QZ_sp!ZieaYDCKB92Dv% zJad_YY^p(r_Y{qcT#7kgf4h>)S%_p8E!Pj!o(5MYIUJD-lVoBUnP4F$sRod0yGAa8 zR@Uc`w^vfk%Lo*TUs?YN()OxAid#fjj^EKDLcJ(YAQLK7Obz_=jQ#nAS#u7!#a%PE9*a`xgO+3InVzn=CPJp zS^utJiL~rxRzE=`4YR@9hx9(iYSxydQ;#@N^4ey3DU zHfNqmU`@*7C4KVz24*&ua;3uPIF~V?+s%?3^#sGWLF|EJ6kb`+RR@E(HIr|{C&#zp zCF|oE)f|=sh3e*b^^H}t9CWCikO;-jO?I&1?y^g*CGS}9>6XoIyUb}cr$4x!arlg- zGd(+k6=K-B%6cvwgNA3#SX!r35XIGTL}3rB7Y$Z|nJc#{n5*4)kRqkI1{54ik}F>}TSZO~|V;o)$!N$z4|D!EIKV3AN%MNz%7Ljm^m6 zl&pAakThAcMV}As_h|-v_6e$ljfrkoqga<*!!lK*>#|9*%u;Dn%p#d8ky)?|Jl_K* zw|4inCA*;VehESVb3FAwJ%xsguR$x5!|Y`nQ_r0~jcgKdb%`Hux#=U9 ze)zHG2V39SbKBeRcnK;c;TwM|`P|q4>*rT~yD~C&XV#_@?Vue{`((58mDIh0kB| z)$9H`FT^h-{IVDR>EbW%`~LSn*Ld-wb?3{Pdc75v?GskaA{k;1h{_KwC zf5n3Y5`O=MXMXOVKl$_vzqjx4_rCfs+TSk3&%oy@I9?A!f(PK=k`jW-wg=(=L_R-( z|522c&)nkM>HBi&i3YrTH#5_4{((&!F4%n&8t~LjGYvOn^E10Qt!>(kkIIkFj%9Y^ zoff&w*zOU0k2^mzwswC>1ezLcdc4mckE%5`uY~h1C(WC@Y?k)T^T?-^)tT7QlEmhf`|JekWHSGMTO{eG=9huCBK2}`>8E4`@G^4QwBcnd@Vb|sk}dGdAxmg0H1_3S(of0i z&dbkah_n^R%c23Q94{Z+hLUCb*T7|%wks2#Dwq5YikJPZ67G{1zpRP0h4e^NRo2TQ z(U4UM(2kI(?>!yQU@Y@VjIr*<5T;uEwGLH@FCz4Q3HwJKs=^lJ+`Z3Z_{a~huh`G` zM4Xtdyk49DQ+N{jevX-E;iBJNz$b=zk#Sz1!$7YbKJTA_`#jt_(MclqVjAKwgKt4N z>bljzip10?{-evyjA4j;Wj!Vm7!u1(~fVa}JV zXMU1@EHV{-`$4U!mNb}^%xJ0DT+in}dEEjUe4j}84H_)N9ypd`4IHnh65EG7wptw3p(^nS3;UFXJ!xS-wy+8ejTOC09jX$j!u{fq z5U9P`N>hO>44+esu0SOvZZE4VSb_fra7&;9nT7@B^ot8C>bezQEz4wV{jpN+#@st0 zE2U8N#niOn$ka4NS-38j>bhjM)CAToQ~Bza&l>W2qpjP}>rq&~J#gO2Eh|%%TM3`# zu7OY5Z--Nr%aE#EhN=Xg;Zv|9I#eb8(!!2e*aB3a!dt9Ec)x;$t+6mv?$t+AFZN%b zI5Ase>-YJ`&$zGk`NxlZ@4EZB(1C|YV=DR_#ITJRv9h9hPxlPr$Y@ibqD>k;*U6O! zb=~UVMbA@tyywfAoJx;kiHz%EstJ}>+p{1PXxD}%{78Kq#3*)n{3T73eY)%y7 z>ro1k!%O(4CdUu{|4<=5s}R8aQ*AA&|MhhR>MeA}+g&{cyp7ok>Ign^qa_bf#wW&eUFK zWNLPDYz7AR+IsXo;wfM>!txgG)1zMJM*4f;yyp0E2o@mmb@)~AzoiBJI|wU5Go%E~ zka}I0f_)743WgSR_=jtbroP#)Mo&jl-~J#X#o-s~a;G1Dp(1z6^>r+{&@!!TxsN@s zy!%QG;CZ-(5Uv{TFT`;iHOOCx6DW9p2iywuvV{bH1!BDw!G3xnU`FtdBfKf_HZZ0k z4*la+@VA;*BdLLPb~4LNx+~@GMkP8!EPA)gkuphhOv95lXW+;H$JO6N7inthBGi(p zDKBd>iTWpd-UapQrfyAl?|Rg;_kJS=^wp9oH&>83`(0KPuW3)eyGw!Of0kztTqRsL z9IreomSuedeDEcH3;s&@hv2hMzYTs9{5#;c!2fOd8{yvypEbn6m{JIaltM66C1Vtf z%AjD6AoPb4@BipfmG}-q?~$=)%g6w z=RSV4Vte`Vewp;hLulf6^}Kld7iSl~_BGVX_alke*?;u%q`^6{o}i-@XR9QGJ5@@_ zPi@@-MqUm2sT1H@d9B0y!PAGt1nzjJ#UGbwwP=4yxrM%4-mk`en;aL9$ouPYqQH=toz%nq%$TLb7RN~? zwy7mw?s;LE_tX+Ud}s2SMI1(F-e zeVc^c=1K15Mz0Jc>nYbhiFy#I6|($lMPL?(0WH_GPyZm%7Qy)SXmh2un`+A27FN_O zTDT01a>58*<_Y$R^vn%XRzyz8w3S#B=&gT6F#WIFH-Q|3BMCQEp``tT9obZKcL|sg?|<9KdIpl!6)6Xz~2a;!unmfMdH&s zq()(cRf+Fe7)MtMmVmWqs9JDpuVD2Sc8Y~J!xSak*R!7(V;4_$-*FSok!ln4p`XVSlHiM*rIYnuUdzy z#Az0GhK2PYL_3eyTIf)fcr8Njm9P;VsuFi1r1*P_4$0LnEQ34&Org8fhs(cs;Ug!S z`%etl9DbnYy8GE?-T}8l8q&KFie3a;jTl~)$_uSxa)iAhF!Ny=up%1ZczQ-%cFbj# zNYD&RT^Zrn>^6*q5@K}3T6)8hcU>gLx-SO{w4*F#Ve3s>RxL4?L5HuUa*A)G426f{ z!KD=r=-4{QGdSjej*XlbL2BVt&XQUsQ2nFa_P{NGTL;JMZnQJX^26}S*Pp;=N&XCe z1N=XS&z#tn)!2<8HFjgDO7`pu#`%weeM*O_#ot)iw=C?t7FLPktF$#bR3)ynu(X98 zu&`S!4C6Vid#TF9_dR{|>J!gDdhWwVD;8h&aP1w)K^*z~b@#KVcf&2jBb346%Njt; zb)F8$jvHYPUnmydKLfWN*>(ifkZFi>E*z^+UAH>kZW7%;)@G+B9NQUEDHE{f#h2?& z2j;9K8l*TYyG1J9sWQG6I%{zKT_Mje-(U4TmXOVQ9Os@V>mV4khs=FMHR~=N3@;wzkvpWqw%exZ(Iq=VbPuZ`6PZfO! zoKjJSl!`J`B{-BS;v=cbok!kKbKwhnYtOz7^zj7MvC5;ZiP~dBi%yjPYx&pj+;!skQz=+omom>H-9bOSf5pZF~zN6Ea5OZ4AV}fr+*CU53yF zf%wN|yvmIYVFL=+7?=Z-C!%p2@tE5X^gHC!V`HcSHKI-6HF9S7L`%qr$f5?;W_wAd zlZ~aYS!Sc+$T18X%4dbyiT zDlP9A-vFXC$kl3P8+YVL8RTaX?^SxrZ4aDR>7N$r4d0l-9%?`wlYmEmznDMc@IxnB9)13q&8eDP?Gpl*nRj1zf9)rFYOaT3B8fKO<8-q_XoPmE1{Jrqcg?|J5 z^Wg7?Pb+dge9D(_YAX9=Wu6&Q=9wY27pq{LIVjlsb*Nf=*uuVIVGmo_&n@g17Pbd9 zuIP>FkQ}iN?tuAS(ekrfvA%ZVjWfHCR&0S9-Z*sRy2{&6S~XzSa{@1$Dgb? z{GHmP$)6oMzVrAKm23XB?0D_5hmN-WOx_&-PG!Z;vd`BZyRZ78J8Nc+|Df{D?wLgA zWzXk6=R8<3BaYlp(=FBbD^%Yc+zMe7_cq*_i*>*YRVgp;awGAx8gAlg%F84rWp4Kc z;%Ukg+UPAroD+x-n({l*b*u|C4D!UZ^m*P^U8Z4-WG9>VXAZ#FU0MHSu$2(Jqd_O? zSrWM~vORE#!!%GX)l%7&!3G7)^bgQVnug>eCP2JRZ6r(LJe7WB{rk}(5(3P~tl5uH z@4S5p^-W!hf)OFJuCrN#f}`?H)^k-wjc0DacSqbt?WR&@F`|&(;T8vYli_r`_k{kOfEvGjMkDEsd#;L7>B`qvvVUC53TG)(*-DF{h zEey-;n%;*k?9VLh?=0-Ng<)$<^YVy={lLP0WMPY;dAFie)nbVbRf$(v*qIiFMI()O zg@yH4*wq%6wXg{bJ7{5Vu&_@d^!qYjE_5(dB_2TNT@vVoSL(S3Q?=s3RCNO5@$Mt37kX=tRW$CsEA`@$)N?vmSNk`^aH$t- zkM&ev`0$%kwa5Rb^4u>~AHOqI3oxR3UTk^j&8h0H<3F!F7tre4e>VG9xJMsRdn{F3 zF8^;UKmJ;71Q@&D0glbZu8I0(njGyu%?xqr=X9KjZ)b$I`y7H}NiAfzNt0>c1ow!w zQO0ibgD*Icj~p=!2O5lLlY_PxKG)^9(`R{8G`lI{4fN?U1zWEgikm!4SqSH(B^`#q8S_#jrBJbI>9QO3Res4SlYKWef)?d3-?YYw$wa3n`$ZfQ-u zNrqrpjoD-^unu@nY}CZjTKlV?gYjU?ux9_@i6)iF3;Xl>H&Vl(a#d3_&zGVu}k6y~47XKj2GKD(cf z!RIveFW?Ws|2X_f`1io4etr@@>AV4Mk$moip=xR88B+Vh3Ia-&9V!Beq_;I zDeO`9mw#RFF;UKogd)~tSuZ3Z=P}6JI zp(??#;2(f;wcuEgp(??#;JYP^V?ll9G_J*37)gZL!%`e>d{feg+WA&@*3wKu3 zZvELmcV0HTqV`QY(Gx%QQE6zuAXcMAE&(juW>40sJ;`65GX$!M-KsvVv;)ACxo`e|=E*+33rltQiwhMU~vxzxk zGbex?g5HhEpgVuZ4TlQ27Dif4vli?w8F1oQV99_9*q)fx128h~Dn&h@uV79vcTpo# zrev?@E)j5b!n-uVSaqpqAXv^?n-3nJz{91mF=~-;Kw>VpSy`cgC1yn<&#b0k-lRNa zRwgy;fX7e_qr_I1O3k`w>KiZskVSMdlRQ(c)&X88QO~idjiwNnc{k|Pvl5RIot~Nj zw(5E~{1f6qOscr#h)ILI#}gu>qY{Tb9Y>mMuw~f6qp0)pK9|YElB>r+7E8!OD8nvj zN3m*uyKL>sv{AT$5@Vnq&4Zjcm0DN}CS@^7<>*2o%{y2Qv zw+Z-fg+C4d9q_R$Ay1lI1OJb4k52B;2jOEO<5jvH4Sbpp=B2u0hE#XVkXrsxFv>*1UeKXx@uG!Y0A)~k7wb?JORHgn7RCi0g}2Yb z-fm&PXJMbUu+Lf8S1pX^O*AhS_M(O1p&6YAwpBGA&i-f^Umox#SvH)<(Xd_%cg=82=`T_o#(^&BA_cVb5CFOBPm!zU56aZG#R~i!~P3YGEA~ z)^A}$7Iw3R{g#Ej*}~pxVSj01$1Lpg7WSZpy#=O(Tvdy=>5!a`VK!FN^5~}_W`RlB zsn}qstUXq9Y5DOxD=uxr(BiVM<^J1wt-B6121IjRr~@>nyeKppEaT3TP&1psyo(Vs zR;_TLmCDPce_Y0^yJrxy23&0j%x#z_(Jp}Fdo$E!I%&MVA(xrRV4us~uvLrfv>wWA zFN1{%uN$#TVb1OYWs|fh#*)%5@HLAjsbSglMr?21)pVwVVbUw|t37e5r=UGq3Wt4A zX+>pF|8r>vcWEclXSu7?l0mcfyv;*_GTH;jfzsu0yp9WXobLPZDTgQE(}?{5egk~0 zI>@pA58<;gZ-iSUN3IN2%R^NRVf|9aR*Q#ps7gF;Vc)c{6BbsEdQ@qb>rk~g&B8WX z*ku+*)1va-X<;9-u#Z?6$InuO?|U$H!lS?|HnqOF=S20FFoM49K`1as!`qI(POq3|2~?Yp+;@yJSI5gWS$G)*1^EOks~rSl2Q8lYL70f1xxC(I&rW%G$Js<1j-@L zi31cSLYH|UfkP%{tUB&zk**caT$I-yI3qK{{~Dxu{~7qy?9akKAO5}YDc8S)PmTU9 zIHl1HDUD{RN={W2>_LrJCBCLZ)#B?G#(Ap3OQ0@QT8@_#jOT0=jQb)Ah8-CV!=OOJ zhAr$K3*+jVN(+tNVNWJLjdKK8oG*v{1#JH}kiS|p!wJPB4+2W@{w~}KIRpDW8KMsU z6s`l#Tx)fJalC?-n)2dh;=Pudx_cb1C18n3llT|GaVKA0#u7)LO*iJ#hf}M-45?LMhSVysf_+TmRf(_aP_=l}!r0F#yz_NP zt(3~WAMEVZ+?A?nxer})9d>>Mw)z`(yzNL&4L17|M|!Z$vn~N^SKab#^;hrgslMzB zx&L@A>|M3CciSBAHqIC_H5bRIEGP@Xi%LO5Mi_lIHgEj%h*uE4*H}4kd@^A0?nhyQ zO2a%!dpjK0&(vj=25&T)n3kGQDeYZpyF6;oMyDugm#0qVF^k;Y16Qt9U2jdJ5slGP zava*};hu!De<@VD*|1S|vl+LvazZtlo8VIx2jP?b zH^Fa!e;EFi@S*01Soe3pXFj*UDWlAgGRh29;aHW5trlO_p(^n&7DiL3@P2M#G|vjg zWkf}f%ZLj0Dhs>N!Z_eicv~zCvn&l8v#?t%?2v`M+rr*!VSjC5pRuqGv>KJiHXV|U z8|@d(8%u9XYtP0yg}^b&!#_yO{?r|5uR(Flb*2u`PV!8#gB}MNtN{PiyDqh3t^?M_B`IgH?vhQTv%6AQNFOQ ze9^+n^74gcH4Dl~Z8dOlE)Dr|RKun~JIsUV9EFd_KIKO5^GAzi^a^wZy_owivxSmi z_a8yoDXGFpLu-9@M_>em3O;aM2Gd z(8lpHwHDN)Zz8Ta(9bgs%g?@$PZz1n>Jd&F-XQBsX%P;~Mn7t1CRnAbQQ;cqOo+u` zwldRT74w+_r7$=&b&7hXfTqk_-z?i6IB$I)!SV_3-vOUx{(Zfiau{J%-wdhxW=OrQ zL&1*VUco-8LwIYCg;k*T6doTNPtii%ixBHQZFJgIu{^18Im06%VEtLKBI}vgZ zY0BZ)Gyhk(ihqSSc9pK>W&pQgof2xv~(2dj&G z?tvq(rp%wfFpT&2z$gEo)Wfnn5mwd3kg6_*s^pfig1rm(3igB!Rf`{5SZp;M1-#Y0_9h&hCc(1Ed^S`6NRhcWZzEltJMQ|Eu}@^Njljg?$uTCce*OxjP$B17*bWi zP?elQD%kJiUcp!a3ih;x*-nS`M6(px1yv!AUEK<~RfUmYOlR~;#PF(AUdU2C33zZ& z!!)M#bMIYUwu#J6{`$HjQ+FIo6*grhbxoYy@-khMs@qKpDF3spd*EovFM{Lshq`mZ zm{aaad=Ne@A(q5sbGr>;RmTjeI%Y_nQCBdUF9rLQ4ymWy6l@u~A%%CU4ps4>s)lh9 zOX0QhOy1h;*k{rei4$1sD;KSMGwJ-=#zw6CA5xIDV|Y_-{>BWl;Rr{RC$3}AcdZ@E zjLhy^Ge{stwZM6x*~~HxqQ)8GJ!`)_!4b9pTAR-t$gi20B(wsqJV6OF*H66TL`sFc zc`cAQJW{|R6R!%ntmLJ`;b?h+y$T8W%Z6! zn9eH@Q=Vu*MwAq10=6W%3c&!T2ISbJ8#2qr0$K&7o-(fmjX(~^w1RaKWofV?f0BCuFO`k38 zv@0&dT53?v=SZAY9y$#nI;$nlBlu7Goc`ST5&Cnk#K}WZHzLGqb%@RyK+6*s%2**j z^ozxJhWVjZlqY@&Hcfr43DJ?gUBdJUKmX!8?+(*}DFL0QJ#=0fqI15)S&RQH*E4Tl z^(SFEYz^fJ>`m)ED}nEPp^(0I`f7>OhyT0=Zkql8&pI@Fr-#D~C-(Zh>EbXX$j2L1z0jD7$8V_`a%NStmU7(2E$M2AyCW#=iM z#HZf<2Vpu*5@#jo(BkuI4ADWyRg_MP#PQN;4$)x?EymA!iNoom;b&cl&IXA?En>Oe zaZ1;Jgv&)OE>Cc+%gASgq~kd9I~s`P)c^`kE}fmpsCx}bk4)wAJ_ufXKDs}rK}^L9 z#@1d6LMvk~1)=QBr6AkPEqnz@hafkGAV)34VyKVwh%7y@LFpjJZHgcgN1P8h}ZcRvQ0xyw~*Ip zNP~s!*N{dF;k!O~HCqTqj`CV(A%CMGbr$kv4XFeK1{2r6YeAkvUd0NP-1*ocG=B8~dxfO1SC=|~(Oq=}$M;FcL2nY#;FJA&7m>Wi6{CsvqS zpU-2Wyd;h=?=)g-QIOjZ?>O0sX~)6WW(E(=1JwTI7|H7Q-65P?_ucHD>a>S6?aZZ5c}r`yd4CARdv2O4M8t1#OGXq_usmk zV$*3Ab#30cA@Od3!|sCbl6ao^AtTqoy)l5-P}jf5JC`EfUnPY2An=WOnl=qDp-I}Xlr@yHNTJQrmX@;QC3#67WFs%>0)z zv7v++DZV&xmKwZ~;_C#?`KCKRQheRO=`naC#kU1GjT{{ACx3qroUI0Lr1<^;IGtwr z=xwoOX~HaFDr*4g;9QcALy@a(|T z>4l_H9`<`LdZEdqdtKMep5?1?0_(zJuau*JDVXK^w+^o2sNLAz+1u0Cv$DVR?AEuH zHg7IHx2X%=t|8&jYsQ>d&!jNU7Fy8}-MPf;lSMzc17Kl{Rm@4MrZg(qG7 zqeox;;g-jy$vIHq|Ht>f@Ne&o53PB1`*UyG`mS%>q_>F`g`U58cKPBhXFmPSsRci} zxA1*6vOyd8AKDs!{hL$Ye^c4l6Fc(PT=WB+D@DRZq4b;A*mW)nrQf{vd*tVHWT4U9 zRyN{gWA=)$L%z<--G|n*q8oQ}ZRqXZh@%P1(5GA1V=lKkgj>QaA7{NMY@K7_jop3d z=a%;M53K0!SyoY2e!gU40E&sXEZf+*%;o~l^4Yj~ZDz$B;@JFeUbhZxfg9LHc_G(` z)YWd&;fTq9+Zy^_Bi~OqVxDY?`!0n$*gJ9LvaeBJ>T|HE;Od*y+no;Oj9@L@Hrg!ndz--xP0w!UAyL@ax|&1Hys^NF}vU{YYhKV6BF=i73(y?gw&ro6#(EZw`I zC505NK}j8FN{W%PP+XMBGU4QtHOx25gx_|q0nR`f@LSGq!QODNMXTV{ixR{&{Nf%0u;XAi`|qFzmWv*|dKU;U5+_$C z!I?&hEd4dWl?$d+b%iA|DX1`h$E$d1@mO=Vbr^dP(J}?%(mvC`t#vIu#8=Dv4!qR` zHjyw+hCK_<|8eC#XlI6Od0*SrpIYAB9@mdB*iwrrPVS535JGb>PTnb9lmkoft_L#7 zQJ=#TEPBZ(BSXndhKy=1ei_axz8k}QvV2L_*#@=~*v$Jb*pxZ;R5e`M|d58$6P> zJ-TZy^Aq>(IZB*GbWRax$?$_`AhMG#;@`lO%7+U>PYgYmdtvUtM8rUvAVr}6 zc53CL-`_Lzix5L?n!c^Rv~uUwyX$4BoN)P>2>eDodc8qCTqT%@$AMCDRpVb__c<8L zi`=;ak2Rzgiq^AbNohl#;5+R*@%a6}!>Vbp7r^!IfPYvb$|I6Ut8?*L3j@-MX)^9l z;~`(EaSEy}_wq*SwW<7@RbJ__C5`J#Xc{JgiLX35ZE zX`J?AFT1S=Y#I5m9=L1+SHD&QT}QRm7sz!5$D&4L6^Crm7&UX@@?dMw4HA|9kyflh zocnvHf^fJ=HEZ<3o(5PS?6YC_!#)@GJ+N6e8(~vwZH7(xgt8LNZ~p-MU3mW>>|xk9 z!@dbNVfEHJK>#YeSJ23`O=DibN1dDMFW0 zgs!l68~znW+9+(tNpKz_MLH10MI%t;3;Ux;#VAOEG)6;}7Y$XwzrrU7BYaYg@JbcB zlqz&7pD64Oyen+ScsP$RRX#r=Rn~X)tUr8IdBjlVQA3r-3{@_~XDU_bQmW9UR8bhI zqOcvMa2_I6IuS*1Bd@>qoH?RQ+0eOm-N4$>&}B5d@&`ke*9=wA!xdhsK^~PVbSYKn zQmQD7R8iQDJU9=LD*LNJKbVX(#AK2weSKYru?GFXPzAHiQiGl}RAFCBsX~`hg)XIv z!blZ`?VxZz!c@6q#2N&uq-$13rmS(z_eQ-&%}8>;-oP~~Dor&OU!sX~`hMPa0h z!gesnhe(y>5?ejHea`r6(4)>L3$M&BA58@s6;+-$R6(Cbc;y#{DpkmtQiU$13SCMS zg^?->+rc`2gsJk_eyB29W*LoKdDc+nr-mxe8LD91ZKy(*QiU$1io!@0g&o|+Z7$QN z8vjE1IC$lRxI|A^()btWa{wOQ#_j1QfatFARt{d**0$T>lk|LQ)^LCg7I)h1{;d;&$MW=ZQQo;jNAUL!Sr~z zKOrad1paM2**0$5cosg+r~3^!d1_u$HRG;)cj=IxNYO9y5~QUcrZVlO-_v`+s17hPtG-s(e!w@ z?w=Y@wvF31o?Q<sc zBsy1hb*@Qt_Vldj?vfpnDbw2tKc?V#;aRiG%5<-q{=2AE?lHSV60@>}?BGDvtdZyueuaU-W)fv z_>UNSguLolQ|-b?Q*A@EZD~t1o~VtsM4M`(O*KoQRAFNA1T=i(yqf0L#G+_xJl5Ql zXpCISw+e~laTiCtEz;H=Pt+m0SW|s#G~V3aS`)>YpNYjp8Yc-Eq?+cYrf5wY@NhOr z{d4^OtBOE%f6G4dY9jko{U*r;7nLVg7mL=Wlhtz2aej17N!h5Oxkia)lRe&#SsOLUT9Qxo z`;t1y6I0bX-iozg&E5%qJXFXw@N;b}-qIY8v1lS~Z75pD-zWO9QQmFQ*4AiCb8DOZ zAgq^ayeIiFYZ}05HIXK%5lwBeNL!NKPWB_l+M6zGLVZrMkQE%K_|a4>uz;Q5IMwgp z8d>ZzWGhIi9|1+VWNB@*%?OuLlj+m^IFXu~XiHmbq^Uj{cgaliW7IS^UlxldP}|yY zO_F~1>8S{fEs>hGL`!o+tY&EfvMd@~6s>htZF(xQ#@61_0i$DsyM{6vm%0qjV*0h+SU($TUNw|Xe7Q6rwA4AoUC{hzxAz= z+Nh)U3_q?R;=REpL)X3ur2>#~9C_~FyWqxFl->ht{%?;>$Dq+e~Fw$zGm99AUtoRjvd|~(K zlD3wHNUW(b7H^ESq1xKAsq~|^v{yI8;tL^ro#?lWHrtO!DbNsEnkvz4Q!>Yo8IL!# zFG--%RzpZ#hL5(wWo`;qv=!nnVJl`bb&Gv|3U*Vht}a@eNNc8SeV*sXo;$lbhHBQ@ z%pOM^LsunH3J%)4Hpe*g{h<+td8-?)S`k(LoBN_eYIsfX6{_~xGO-BES^RLb5U+w&(8U1UVe_cj@-r=Do zTc6QCiaiMvi+_hc6UHY?K;*AqnV?b6#z&?T{U{E>Mp1L7-?W1D%NYL^Xx= zYK_*T*DVJXBu09=#OS&3vW7<>#A14mGoE#=G4yyEmby?m#v>lBX>X0SEluDno#%Mt+1lLPR@+?D-pCfu zMmfQFI*(&aTDis}(p0msxz%I0i&>axz|vESCSq~4V$pa_q=hstDDH3{XJ;qmgy0$Q zT8hwW{9bZC&k}*-2quzeGsS+9Bw~_a?}-RU8HAQd+rmU0nlkxd>l-${AcA@l4g1kF zY`*cOD1*K(1r`{fh>}(ZKH7rOL2it=C?;8O3|%1`MWF%KHa9|wI|3IOuy#&E>gsEEM?T*zL*?%FjkcYuS>(WGYNlQ$-~qB6js|2X5{ zhL27(*Ci-U6E)~g)@yrBoE(E=`jH9O878w6VSE6AV@*sws^SfCuj3V|4Ge9|x0*n)0wtPS7Z zTz#ojg?+%l9a)l-Xj6NmR0RS<28d2tb8D>wk2B!L=Gt})S=r7LJI8=UxYk85-$3C+ zpYg_rof+v8kp%RZU_5G?rH6qXcnZ%oaEQ%F+(9QAXnPZftCVCvLmXJ?Z;my^+NvWE zw~aVp7HdQA6dll7RLzOSF90Rv)zl2ZIjHWQ)jJLJMFvHf| zq@7|$fP66mRD2tryiXq_O&{`QtVRY8jCDdX)@XGzQf_W(Z)uD)Me3u{51`;>+1^Su zW-ev8Oz*Jsw%?z?ARGhlB}PQM1oIu{BGh*_cdlWO?f}P6jIqGsxfnSdv-5>g7l?PX z!^3o>%#k`Oao9qXNe;z+e)9Wf8Jt3gv#_nLC4nZXm7}l(STv4ysWxGVC~Y$%Eph?k zXbBRW7-?%(zLgnK;uJd^DdPynJNyQ8OKL8|A%4x>WQSBAZ6gWL(l%l;w;?M1By`j` zy#@JJY647g0oo$f)fhrmw>B^46s5E^Ot-{g$S_gn0SG_F!7WReHks`^W{olXC&PH+ z9-D^S5Ur13MuklciiE>@SE$E1kp`66j1(F?kQ_|ou3d-*T1G*=q53lh#a7e+RiyMv*8@i>5jfuz0zna*gq|q7ZaqP%9Tb?Lw4z>g1?QO=%q_hFyvh3@}Y=#0?SY zZ5N`%y8*+Xb~K36=b*1$e-d9Sz@4vMcoJVL)kSzPtX*-^u#rSdY)P~sj+SF$G1V}m z6162_+}Np~Y1f=AI#wt!+P2s^f<0TrF(bF@PJ-PW7iK5iE;4B>XmJww9E|cQvgmKu zm&D)D%MR~!dYo8xg-NimhF~X8rKKW*U0g~cNY#^(H0NaafqBewHOfsGhN0|QlV%PR z6YSp8!!9g|M=Vw=b(3)%#W*0nwbRc<38LHeB|)!ih}26{nP_V^ojmEbGkBQ6v9t8DUYIWxFsX2pp)yFrVe-ku8T5G4)uvDz7cGt!kOM5Dpalbpj9r5$l_DNOTETdK&7GSUnd8%p3`)Lz>&$q&5;6 zBNQOFH%Uhfj1{TI>X`I7=!?MybB4YGqN&DgnoyA6F>cTslrNF_BW?VC4>(50OXC<* zVjyE@;xdj8pWQ;_dNvSwwBPkY#P?(CakP<`M zHWnpgn4F5hp_YjL*IW)HjIBIuEa-)KQ)EuOYBBU-^GYx#Xe~I_vPgv@;h3KF!RO-E zn~B9Q2|hD32HvHAoCqfJ=P$CwZkAf{G<6B;n%P%DDsOOiJF>>RaLgK8iU214vV zm|;Fw*@=bH$b@A&O(=pqnF(!eYe>`}Jm+y;2jw{9ndVUpk89CZVtohVOQxYt0*L7) zG9?GXITHwcUOFXxmklPxVrCm-%8#2Q64$@s}B|pL?R5IKUun5tp;_WE{i- zwksQE-h^K*3V)`7AaSfgB-*6pYw#&le$=<2s}qCMJlR^*+O=VAM`u@GO;7K_6}?RZ z>$-ZoJ8QdEcCUx}B4(bE)CyV8#2f48erhHJa$fNc;0Zg}+UUkOWK>?x+Y-mp1f_Rg z@fF$10lfmv0El23Dyg5WR(`tJsxIt0j8aZu<)UM4mr;&HDUY6kOmmVCPPd;lcQ)F~ zykeevWoF}?C*|^uN)Sov=HQ2zGLWPwszHC1)sopCD+H-YEhPbYEl10uW=MCY-H)`b zq9*#j9q)^U`KRKIlxS#4lP(k%oM2{Q%UVIROva;4$`k2os~2S{sul0SQdYvGXdJVn zXx8&&x0ywRPR#1=^(z)aFD0lXHIe1QjpF1}(1ikoGp$H5In^rl`7&lC(b?N?iM*nt zzaz0>U^xa3Xd&{7Ii5f;-%vs%8%vr?Oc`qv1{--Yq(VSUd^AB$NFXu*bCpPtb4C3X zbH?E-bLPgcQh7dwl4q+dCBd~wpkOglN`j*A7JyjJEzMZ`KN$d4Fh3vp>KA1$XXX$E zr{*LMl8B{=RIyu6Sm#kjnKH+Tp?7;!xPxpaa#O1Q*$Dh8lYtZ=34X)a7LAQ%JC^Ei zfN2ZMlxn%u=>bG)lz7<^BW1wp{6brRk|Mv5t2p?C`iAD}NCUVg5nYH*GIAJ~%FPo7 zS`W!FQ^={N{Q3R0EG;WBz!PLcjv^5uhqagz(JlisLfR*~d#K%%a%=-47OrL(u9!(f z#MM#L6fyoEYFu{ZLuA1%jK|Mi8+y2Txwj7yzJg~}h9&;GgZ-c8Xz zHazf8@2z-R&VU2|Uyr%>=rb;PqG$K=U!QW`>hFCRiXSDO1+PDT-uJHk<nQfzdIRSbng=E+ARv@T=jvM-`#TN#7P@lem!MV z$!)kVN#MV|WYZlNeD2AL2dh5Pc>M?8`xno9O5k^F+W3x~=l*f>=}&%Z=DF?D{>Sr5 zv75Lk)clP*ntrU8{({ z4;=*0yBp1u_r8e>UwbNX;?7+>X~GZAMPE>_(99LJJtR!7sGm7rTxfIB6!vrg<~K1Q zF}uX2%~L^svymR+tE%I8c+79^5`Pw(Ck6O-u+I;u#bBC@`x-p#52_io`JtLKo-6?YFyq`co!XEF9X1yku^-a3=fa3t}wt$J#UctX@Xq} z8%F>KSvak*c?@|e>>Ait!mfqA7e|wJkqfu#0L*;H=85q2 z8x}tet(Wj@!V@e$8|DP~-I**tbMj6~uZ#UheCHL#q$|rfSd;);V~UdFaGI2&Ls!ok zrpuxuyR#T*5+FJ4Yhd$0SO;v9ekE*FerPq;`>=87YLNLQoc?Fx(X;t<=_z!&!ro_$ zZ@%b%Q`p@Oc8_s|y;X3T+Gr@R)s4AhN}1`+a`BrWz1P4qNN*d4-}9Bs^j_Q5fs4!b zPh<8hX;Ns6vuMsREz+3f&+nmG4VuwL-UeB1*1=|8*25+(&%&d$q)TZ@mtNJUu#Xu$ z=xH*pe9;A_cquGBbP+Hx;+Z7S*Pc3Y=g@P1soEuPqy0-N-gA*ind;jI+d} zWSD^`*IR~vesJcyP{E=pCdeAw;aeV%q&Cb7`29;7Ysg&=b5RLdO022m9_sfy9nZaZ zdQj(nh|$-Xu#2X6-goi*91rnEW+v6YDC#lp^yQlQA^RW>Q9VU3oV**P4Z2Dd1ucYa zBCyFu=fOS}_DtBMBH^TAC2WNCX2XV`2Z=lg819|%2FbGL!zQc1Jy;DJB_mS#0@w|B zUjX}Z*ihRucqMG$4w6ocp9DDxkFqUY%C>Zcy(f%szW1bYg}sAQL~#|ury9Rf2R7n4 zA)cqrO+h+1MHC%~V?3UcJ@*u8`|3|?f~3VWv=oyx*%VPw%;w-Z_0<19K0Tg^^bPUs zEL}9&6j4x=@C$GL);TC*1n~U%VJ>n)&*R_5lT8r?d5UozH#`J34aP%(loJ{Rm|sYv ziYVwJHLPJywDzS!qV^TG;&i4#dJTjJ?iJ_n9gc;3Fb(q6G|28W$e+_7v-yEyY|Jat zAof-yN+QkAV`(`141|gV6lbzpSeCPpGYn+BK>TV0SU++?rIL@}-#imaaKtkT2x*;! z!~tPlQph^InY(^sZV!JAdU@FPur`iMH?j4h%H0waW#1vIZv$JptiJKJU0oX(mFbM= zZ8rY9fcpBody$!dnt<#F{!?zn>FnLIp}!|_Z5M{_-JQ^duqv^9ZO59fisgw7-8jy_ zysHmA*L54#cCAAXNVjxwW=%r%tncDjvtyutRboTW+AZakWphRmY{Mo=r=$1Up7j-@ z!0!W1p`Bo0Ep)XGV1G%)oH^z5M-#3eSNK4m@2U>`D#}J5qOW6Z-^c;ddxn<&(pl8b ziz^d>X~FT|9(Hj4dWVvYfo~~?BEqxgRF;?ejMI}a#|MPd-T_oTw``88P@tZKVz~pT z8I1^Af1044gw25Aw&GNiK~KU>kb1KrNbhHZ2*Vmul|@g&UV|fu4iA(3765xXo>k?Z z_kKJyly_A)=kHe~L^wu1-nW7CLxabxihhBB-UW72e+isW1spKh@J@!`F~F%Xcx)Ro z#mBK{3vjv(UMLG5+qypBYzgA^a#aJK#)M%H85|3%Dk`h;w<3hIE!qyekFs+BBXr@N zN4~py3FkESZs5$~&<=(zkmyqg;Jps`HsD-mbi-te?|I;T6*wP5M}#IDo`-ZF2F}Ci zsL-&z%cf_d5S^Hl*~Nr$7(^ z7^NzRFC#B+KT@h7QbhQcK7BoO-4HJ!&jn|*Uww4(OmuqHWK1k5*X^l!yYX&J6NEY9 zVfLM4R|7XJ%Pyn1JI8BxS#az2n34$Wsxyto->#AfyR+EtROf!= z$5G%TD~+(B?2dJ-7UFMDiA4HFcJ2fx1+uA?;0ZkL4@=#)ZbKccvI!nSWvss4>^91S z)jyGSpF6)Un^FoJC}p3!&B?)Ps<7;0x3Amyj+EvKo1WeJZqxhg(`1opYdmwy{jyk* zdsDPqaL4uE)V6l+c@J@(z!GS5>NpsT8_WKNm2U7j2|wW=Rc0L2UU{BfVwz)mHh9`~ zOwR_`;lIER|6BBIu*1XM;W(v}>5#{P9R;B%j4EpWla|9MkE67K4QN+t=wa1qvJUWI)Yk5hrG_l>)m!C(6OR z15otwzf_yY$l5#D%i@V>yEZ6i&HuWzbyyV~qu0$bYAqaAe}!G%Q%w{>l^g6_kw)3H zYm^%QBd$n;8WEV0krZdJK&b%Y%~zE1x2P23{|6ltT+{y}I6^l|=wV*!RYVC{<|Zu{NxvZy!ei(cm3}1X`jhs+A;5LD$t6=y&^7${^ z+2Y4jje{|a9;V>RF#~`kI{bt8~`o+ z#d0K0v>zyYrs$72kTdFD%>~OwS4ut0SNqCrargSlie;@`IM>kEwQOVg>~iSPz+sTi zEG31|a!h}E*YXXe7nM%$>fTVwe9kVNQF^ri04G3S`t)TUd@m|Rb>$vrh!dQ{YAC)D zjmsl&bMJh=j@WKTk^Kdqu|e)*gvRRx+A>Fn$l7QP6|5JgJ#0-^sIJxzP5* zbCh)PzgS#5c*H_Z(r?{aSbOhh`6|ag`RN)&T|*bq%j-XS_XKgkjWfJFPt8sDilgLW zxc1?_dx*YopkUuXo;a`HS$I7`SM6eWo=((Lr8x2d7xQ|qxDfR6?a?<@k8hD+!_hZ} z?#~2@ajkp zXKWbGPhG)8#ax$BY=BoTmev=;Fl45-_zjeZJ;%Kifq5*{p8*>kY@FjR@bV=D+wWeS zU}$DWUdCh2KES1?(Ko|pG$a$vl_77C?^na-@!V@*Grt|M3t*F^dRUV#J*-KW9@bRY zlLk*&J4iWFmxfh^hLmG#XDRm^xGxD%j$w$yBa!@gHJK@wpdO|IP%i}540(K;>_v~G(ZD1VheWlML$$f12g%QGpNtc{%*A5l;5~TC5Nzbrxsy-~jEPxcMhfxH zn3y0nS!F93es8d3EM zhK`Nm@$jSKkz~OVq%iQC|72x_u_f3AcO+1PHVo^)5=Jd%FeC3LI@k8}?e7%5kEdH~ zbg-EYDaXS-wRmVsK_S}szCj)~Du+D<_8iz`i@C6Q@R{$-AKzI@tTRecx|E`Hg}pnB zZ@!$OS6C)Wr5-2tydb6e5KnV}QZ@{a6J5DKN~KQAB-VGV8x`Fs3Ci$T!!$`X^4D|& zycSfT6UVg%nU`)u6;fEKLYGp7uCR9({uOq&ab=bOq`BV&sY2OV6`+a@LxL>YA64XR z=@c(6Q&eGmR9>!G3YhHG6tlQkSo|m|a~`=0`}oXHG3F;ou|h*J3@8Sf#S%j?Hk3*+ zx|Cvcg}qPUUt!dCp|B?$>`4bR?WDGKzP6Fv%utyX8PLaXf^>cdJTDE<*@ih9ew1@+ zveZ-3Inlim7m;_Zz+GUrd1CpDhNwXdl(XCL}gpRd%;?Lj0#GdGVT`=oj*BC;wpRJ1#{T z0(*n1R6&IUdnt7J%bhJlPKbwCnKPP+X*lH6oY3p|xA7R|489|zlLY5^AI?!}@vsM$ z6XJ)H;xrQ!$9IId2+*7mV`B+k@No1|rH?<)6nQzJz4*8JDH2zrV|h<+Kfq#2B?ixX z&b)h|D&y210PP~7^NGk$B6G`~+8$-Y(zE}WW6-ugOZ4nRW%kMf4jdNM2J(_i5;awc zviXhm)phj?FKw!FUHwa@M^bu!0MEQ1CuiPoYM@wFlj+R+7b#WzCc~L`>N1%Qsd39}MWg_!%5vs?r@^sN zDqhMFaIXasTsQ}3-sdY8*{I5^N;~uZ2f)7#oVzYiJTh>mGwKvLmo9+jFFZ74vrKp! z0N)IpJq9mZd_BN>_k~b9iiai}9>oat8g0Wv15Va-eWHVKimDGA9KO?JI`huz`w8Iv zJ(Uo_2wgIqd8fXYuK?%dDnS#`k?G9)UBKG}oEg=MM}d?H?+w6j1o z&j9b|z`1v!M2Cjl;04m9c$*c2?jSrgj$Z=b@gn>#2TsIPpb2=-bjE)v;C;Y(#D|xO zE)B@vUx0Hd>Ld-tFynix&-mYkd~AGE&iEUpA}Xv8`Jn$x$oGfNrcRHstG~vs{=%74 zUTwvbdOt3qFdn=53zvxD3XQR=zj$ZZU)9xLV><$IMEtLCM<926p32!6F=m83woMRM zLAZ;P#V6Rq8>Q;&`#pS=a?M?5GwMsqgor;17^;M}@meK51?qqE3xZ?#krzncW^S9BFBY4Wy%teWa6g^gF)f$8-@e@ttRU z?M`m-)ms9iwe~{2$Rb=%%R8*)zF9@Eq`rm4wm;U$iuQbPLItTfaoRct)s z(Hh)CjT>-ri)REkty4b-{U;lLDAI|vM6p?CqTEjm?OpM99LKMV@S0LaMr}kPPi{HI z&EG9CbKCcrrY1w1F-=XrtG(@|-D8@Xa4>12ToR6}<9S&vI_EMTmYTK?bt>1uBMq@g z+(9QAXnPay2j_GEFa5E>8dtgSkNs@{m28EeB$!jW2Z!>QTw1*xJnHHjJwq zL^<&lyb0GR+oA+uh;bf5G{$RMA`k%$qL6^+#2^7u?$2$CE|%8W1u^(Gm2m-l+_c>g zYZN)dAUTps#HPY!HG;=9HN|l!d2@4}BUGLcs%5buFDGBAFbR5;qL_Svww&hbOQSUy zv_)zba)!ntgd76zVoyMk$|9XRbC7YlRy*EqF4g8~)yb&Byu&-uV$i;aI*BvBI@Qj_OYC6Gle;SA zz_H-*EHIVS0?%lv^^OPV;{fr(^pyL`<%BXdYS{b9Yj9b6Y&}kutzD~E$@4(-2If_6 z04Fgyh2-+Uxm}3(Jkk1^FzG?*t9rV$d&+5ue@&9`c|Bpf&#hLi}mq2C+nwEyh(wgR`x>$VzO>I*{400MIj7s5? zi+9*^HCN6jWbuXDP{@VFEIPdv{%=}8fK@L*ewYV#;>U1{4Hyx7Y}iS{5vjc59DeSi zW-L)KKtC7=S7ER3K>+%`o&4u+vghE0RZfN{%`GwlIu2N`5uRv_)ixwz?Y-Ts1{D$= zYa_Z&agJ_Sh}1h`5$n79t8vfxLI|C;U0QQUexAx<1qO$+>aahC6q6k?$<{O=9Wi|Y zBouR@RZXfAbMmyw2{fkEM}>Su{GCGIIu!yer6~{$yw7YoR)+G5KZPu%i7j+wz~BwA z8XBr2HJ4%SC{LD~ZE=`#!|glp7{KTIBrmDK_`wuu`URN&c`CS3WGCb8S4xulhUV%> z1Gpp+U6_Ejwf1OS%8vU{wR(}^rjY$idB4@#20ZT-(1SF!O`EY zD4)Ff<7fW(XXjJ(9rzAs zEHf7irk+_G$Ar&AXIXZh@zx9j`b^uZ?!Mj8=VE=A4(yIT-`5{$+a2Ars=K#;cXaQTwoN^| zqc2u(>F?SdeWfqn1?%+{GiT1^!8~v1{({}?K#Li=h{D+$C={>V6ZnP^g1726{B7TQ zA;h36xw(F4fBWjv?a^mikcUC>Tt?5;rK^}_6Z1)1cMeqggQ;6$Gs+sAl0?uD1mLIQoYXdo;Htt?;%#xT55UC(lqKGm9PD4= z;$hPg?*aTr#PuWm^MGfG_cQ$0h>M4s=ZTB$mbwgys8%QsKpLM~Alss$DF}YCI*vO_~SBuC9~e;^Em6Op#mIEa#fzTs#n~AxIl_)jL9;epG97Jfnq9}5>7FMOTy<8v7DDd{Bi(EZ07Y8XNc{c8L+@fp5O zDuMhn9noQ-nPx#KIY?QBVM@cePIE4jLkTm(!OESBKFTCj4o1e*_*$In3g^1Uxkv=X zyBn?)9Z=fU5NnlP6)bbl41O>CmM*Pv{DJHyPi2?<2+)_8xVx?>pG|kj8@5 z1>;I;=&1#kH5-g0&)64$YWTTlb-@2hGLiTy?~g<5wE^B|oQ#8C^buFesXDw;MmC40 z$cs$DR7f}|-vU#p4lw&kY&3(4y)46&gK2^aY?yUp1}B5%My1$`T+(8L!6psJB|Ju6 zi-+d3C|ySWdDs|Bd0&Qo8tkvaz6AEyVAsL^I&9MJZrJ=NwmlOiHoEe?cN$n&G}$Ta z9tZoWapgBnx(JWfJG!*q(G?c$ zUkba^;Dxn4{49F_+oU&u+E0acY-1^7Cxq;28}N*M?zs{$W(a z?Z#vovU5c-Gxz}n39`H|3t;&yim;e&uz8sV!ZGmau$iAT3?ZxFRzlLHgrrMZR$*jW zg`r4_gy8BgwAbt~Fg-P|Oz>??4L^^44{4b|T28Y()@7Qc~Sx zw`luCVuUYf7prOh_ww=}pbX=K ze90hljQkekmDyrmO-`j!va|;ouQ8+vOPf9KegmU!Lw;feb^>-a>~7dKuzO+G!rlZs z3i~?P)c<)i>`vIQF!&SLP-rvw0_+6r7h$8_5UydG$~AN;*U%OA_Thh_ zz;aNYbcH==%=0*C$@iuhSD4xwQU3^=Zd_q+8C)9QHO3W&8Xu`2KAm`4=PB8VJ35_s zLDBm62pQDKI0-Ns#>y^&nvvSAfL16gWXY(b5V9=KGMfx+rXLis8$fTOY=+Hzz0=U2 zBPpdnT}pqt!XnocMs`&gMC{Psk{x*08H?@Fy^D0vKXm_i%o^;0fY>+i;=Tb@ygU5j z@OKNp5q;&>oEMGfl1m~%=(^DeFTPv{3 z@n0jZ@%X1;Al#aza5#FyO~Jr-;?lm**s#R((L;PyaNLEr%0N45rQ>Wm~NL-CX<5x64<6>PbPi@m6qwwP~4v@B*9JJ2L&#P_^_ zSYRb*Xhw&~GKp{IIVir{Q0F0nIM^8EoWW|?%-tH;6yNM|X!npV?HWK)sY13!j(eD5g_ zB|}}yATW7esdPp#^@KOhR5I^SWa!hGMIo3?Y2xSMN0UuyqKH-aZ<^BmHPy65>?imK z6ULKCY2x#MlfE?RiVVq-IU#C6W6o&O6)RGV<%FmKEnhH5AI9icWJpn%6M6&xHZ7xA z(f947Tuz8hEu@$C{N{f~JH}G>$HSVF6Qa1X@t`#(jxQdGA#?^Y@pS$?cW-(;lj$3p z=liZ=jmM{#jLmLNh?>sqccm+Fq^L+Las0p6H=AwelnroWY7ls4E+DE9|!KLEZRUn=Hq7uAs#+qmN}=^5Uajm8vbe;+oq)g zn;UAWaVS2ml+Dpgc>Wbn|C^zta6K;d*x1#%w!3S6{~@a=)D3Hv3j7X|pPM1hg_P#E zZS;;gW>NpEx76idUH6^nlBIh-zh?!D;jmv*;;x^Wxnad}@1-hiaoRAmd&R$Xj1Td8 zjvTLQWmiZ4%(Ai%qW7;5Ka21iazbR1RO4?{z+J#0gQOaRBi$-Cf0?vclNRAw^XFCi zSiE$9JU)L;nW+=x@e_r|KY5A{1DOT?2k@QQ=PGN8$-v{axt{lT!21q6C@>6?jmLj! za0Jof1vJ1G0N!aEY=c3@(YDNs}mdmcAc2&oE*b_JcBMCOsAK zx#$YDvpWRC0?HKMO^B}>IDa&wQ=(^zk7I+sLzn0lJT%$j`y%4|B5; z0-WC&ylmggal{{iBfF^)CfoNi`)feNEhHpNw*0*gzwN-;%B~U&`!1QjcPijK_VK*I zBOhd~X-}``bv%$+&9w))$HsIVt0>NaEqod?-QeGYM5 z`zEwehoM=LHZ_D|#5R4opH<1=+o_wpbu6Iw9J@0LiqA4N0&-*BhP7Sm&{(3~>{*Yh zKH~8!?$kdGY1yMmX=jZ_aY83}9wm6(ByjE^^;|*P(Ew!T6+Cy~A-fla(l?!7Ch+u4 z>i;P4^v(Ty1)jdSzX}Nyg|7RLEmwZ>g|*H9^X0kC?|JlH7+;~q1w4Hd|MLP*-<1D* z#D9;BBQIFC-)-ij+ZBuL^naDxc8~Nf{e$^vUnTKxV}DaG=Q|?1*AI4w^Iy+?W|52s z`x)54JUev*^I?n0?E#->w}8KdI&8-R=Rla=kM|lp`QAgu74}|(t4?5lGOo9FV|0VP z!Lqis9<%+vtMhOHo-UuxM@BO*mY6P?XS%Fj3)*PPFt))Y#(&}|_v+bHJHs%!uhO3IM+V`AZgjkLD5*eD17xm&sPFvXw!-=EJ zYAhv#g^K|uwnC*AF2nG{*+(Ol)%Xkd&^GN%Haod=ECoe5`0$Z7?${DP6^u5z63==Q z-z0B-vFW0E^AMd|S#7bO37g-44IXx$Yw^&0#1#I`uu030!RDah7TD}VqsJll^zof^ z<2#vy)lQj%E?udkD=aLbuWx`Etve;!)}--Xjk0EHI41W*8S1avY44uo_lm zLD4FN!^%;LR4CEaI}VZcPS5k<$}AsDS3RqIn2+RY0xZNZWFgY}jEwSuER6m@Q{ACDt{jA#CJ@#37g$z*y{qol)dOu_M$6H29=Gp z`Evc7!tQgh2aPN2{l>v4>lLp9B}&f7_qvQL%%x`&-=J}Yy&b^uAf1jHt}1~wZr^j* zfDK=18#BuzGY)4!G26zeJsuV_fcoQ|A7CaMhU7~QZ&Fs~bwd3_Z2u&}*BNPUVEkkE zk8+4jqV2DQ=Su++cLAcb3$|4R7{h#BgNHHB#zTW0GJ~|g1Dg!66E>P3-oH7>{O^KI z-n$r&793q#aCC(|NEq?WmmN3?+v#BU8&}wS%E36Vr+9nd(oz}r_C3dvsK%pP(z3S^ zW^RdL#RSWQ%~&*0CN>Q1)A(UxQpzNi{<_j&tJr8n`Fy=Z6%m)20)X>nzDip9$Mmnk z!^&YR3urNjSFZ{-%O+xIj(0rS)DE=J6+n`DeNwTXEs)fU>U9& zKYAV}vHd1U#Le)W7vNzVhW50~L^M0m4~%U&sY+9UI4v>#Jj?X1!QEUshZzmw z*#<+r1%N5>=u+a*74~k!zrt=eF5O_MuzQlQQaI(}>|oz87ao2Sq*(%<3j#E=VaNz) zW~Le2yX83I)Hez~ORLX}{~A1g+T3ku^KXVW-!!zD2Rx+>T}m6elr{<@Z4}0hrqR65 z;vL6?wD+U+bUYwI(pc7@A5E~^%xG%^q+u9lo5f%1NR!fS#&UFU&W`<)S-=j-e4Xo` z*o1BWBoC2}Ty5FqAQmH|=yj~e&$q_19-}|k0Ox|7%r|;~gOpzLVe=c%7m)gU3EWC% zx|Gaxg}qzxudq)USJ->r!Ppon9$ltcs>;)jf^-vD_xIO0IYKfHm>`pG1Z-}gBy1Q; zBg#89Dbi7v=nt$~bIeCG8!^hbL72BnVEV_TuEFD%l8Zn^fOuX`D)v&?jOhy4%-9( z<#@cGBT$`9pz}Dgny1*a;40!Pj1Au*{&@mphwu#aV&(_RmuV7>Ii2pxH>IXQN5smW z-gRIvd-40gh7Dc4iRC>5>p2RD6f<)t;z6Gh^F8B6ta-_O+r4hzHmVIwo_P;piiBo@ zmprwEfsObc2e|r9!uu7)t!SoS_?<{}nlN8!go z0qP&=bPXQX=6*ah??S|+-Fsj&u_4%qfrpFac*OOvNt*Y;E`@yq?9+|^8L)4}J3r?A zut|dLusLe@2iPnR#zTI-5YI&E&eN6eebT_f-uI0w-}`q5V=qeae&b+AqvRDIaI`<01dxa%{vy4x=%9`F#89n1Ws+&3Mijh~JVP567B0A(o1b$LuZi#lx0KFTUn? zJw1FC1QA{S?;@>oLR^!!-<2=2*uR?36q0-JmOps)gX!^bP@xw)lL|CPr^O?!eP}BD zSO)(*^qKnfcqrRa_wr@if5_NKpCuc=yf-}_4j^?Oqs@=mf9RtROI-JY!r>iz-kdq< z@vxrfgr2}ZxrAm)+ILZ`{hilT~IaYAE)@<{0OjbAsS-Z5d1|W~%!_wq9yVB`4hYuV#v8AuA1p zJ9U{`tb!T{ch4&1W&R0sKvfgI-`lyx-u4)VMLprzKvJU*nLqaB289?b*? zsW6b_4$0)cN)I`l>03W%qm~mQSEieO6OZ6{*W>LHnTx8rr2LXge9LF)vvXBd^Q-0u zH~3*QAbu5PiSDlc;GNxW6p*s`XhW z)+!4p*&)Nus@cH#L;$ZU%kII)1I#6OK3T+sF2!@16*DH~OgloJ0}p-_cmqb1Q2u1v zp~E(--q$-~l$qkAbZZ3O$)*Wl7Ba=h{59KV0&bd2@iBk50&fc&AefQzcbRRh6*Xgg z%-`j}JIyq8Bjqn{o5K;}WBxt`ymwJ#!;F-_W;RGZlj(bzzjolAVMM9TANccNc8A`E z=$0R;oi`h?A9>}LL*8`r67qNk9;yHxfK7F(iIp9F{pE9^4l}T61^%z#VbcZ5V|U17 z|5AJP3-`_)EWP5jmAmi!-dFUrqNVi9Yyn}|k@`KJTn0MGJsoDxwSM(7qma$ep!2|% z`VV&fTv9n0C2i^J>^k4i8qHm|CxK3sDw%fO4g-Fqcim#}d^x6vwng8-f-4qVD|haW zinJ*_br8wp zc2M+SZonqUo*M_g^jj@{o5k-9IYdXlD)H;5(@P$RW^b3XQ^{~!T&9!`7of+}RLr3> z37ElP=v-ii&Rl`pEN}cMzHLG1=Hj%ON79>y-Ar3{oZ4m*vtY9v%3w2^)9~nI4P81} zLsyu?W%13IE&B??h{wP_X{$cE)`SmR^&kgk01Z4MT3u&9Gw zGGE9`c>E9_upKt3cK6EC<7Em8K8KS0ScoGP#9%^!YBh2Mj4t3Zo2A z7-fLM?k+`gM??lp%_ajXD-Np+KqEDXZvg+R48Vkll+!f8w4CVDa-vIRfWjyP6n3yO zpz2ML0Z(L;0XRlC)(=1-2F&5=2Vm}MkTPHaY|4NO4R3MOpu9zw@)lhx0~AIXpfJh+ zg;545j50uBlmQB(3{V(lfWjyP6h;}KFv6 zyQ`4g5s?8WWRn57df{;P12E}0h;QKNO!@)nf{F~74w#k`U0P0bsSHrq?RZz%ky{kt zBulCp)uMoJYGpiv=Y(uub?zUAA5EVQogg^Rpqf%+D#4*MB=b9?r7lg#7t2Y5{!T6;8=d=ILu)0(b(L{6d;=+IJNI zn#@nrPd>LaJwKdPNzG3|T0FW0VEdX^UNP~D>G5#JC6zu<{sR~d%ZY|6Bec*@QUH7` z1fvTv(1v4hC|hW#{6Rx4Q2+)&7P7%W3Iy^Vyd|>qt<&H^OxFSjFwvt7KwLddgX3&y zdBvRBrAf2D8O*uopKs802J@L0KC$$5aO!#H!wz-^^R}GP&tNXFC2P{mG=q6H{JsIa zW6aDXi#F4Y*)1rkdf@!j%qFtZWtwqhl3yX8`%I?zo`L^2fcIfD7W4RbO?=X1T^7jfn zt_RL$)45@_%9Ov=fKNg%Z?l<>$W|Uz;Dav!=hvpu;aUgd1BV{W4CX%}_?ja%gK6|9 zY&HrM4tXjQd3^~_DW0?ge1VC~SAc_d(qpj{g}yYuYV#QzFFoq{@@LO~{n_X#I$QZ( z3ZX-rt<*1EX1{P*@QeRuCN5`}*%LwsJ9+BnKwVVHgH0(nP#ok0tGVRiaO5)(RWj#C zAfM@xC&}VYWu?v*7ouvjg?$TWi--13-+>&cMz!JS@r#BBO1RZ(wbue=>_)#D)v|A| zD{9#{P=wPLi}x_V@QZ-1F7;_$KX>@S%10BaYSqpKCX~_OzZ6f2>|s1jTv7a=BQDOy z%@7x9@hYAbc&uUb#qdT7dLMwB^_{qcMez9jcZ(l=74JgWe*eiK`mn#JW$_f=gL8jO zlWD~8T*@5@V(ffXpz7<06$ysCPV{g5JF@0yoW(w`~oSH)!jJh7JF6-Iwq%Lc!o;=B$Ttxa?qm-AofNnWA)eTy9A`w01MhXdi z=*_%xf^a=@m@hfy+ZybbP-T_dIZ)##e4!VQRfJu;kdc z%fY%G-WCUYmxDnIunGHF2U~*HPt#atT$n2_MYcvYM(zM24GKltra@1b6U28N(0<+~pnZD3wLBkW$cAL zzrt=cuCTY)!CrK*yD4`LiX+z`VEqWIHwBK)**H@64vm^8N5hejE`!LH%(jyw?QA>g zn0W?=97*4NIXy|2aOA#$lUB>2$K&@6lxX{#WYN;Ac5%d_VUK7@aT z-E3T8@0$+xZ3p|ggZ;|EI6bRjxocVDo8w?SE32^k9qb_o!{S4rTRA;Gd{rL0mdB%O zS&-JX+&55)-X%C49Zd50VspbyS`Txc_Asy9gKT=-q`*0VbMfSgh$)4uM9!*B6IToV zwTrnNuGB8(^?+Ej8V*vq)BspZSUxCO>0&m*_WN_2L!S6*%~}}n|0ev$n=U5fsR{TW zhi2H`_3#p0SK&R_P%uvn+lGhCs3u!O0nLO7oILhdM0=%#b`vjk6^VJj`Y={h+n?l&26jHXB;05EDy~&-jB`bu4l#4hwO!<3S9h`tS1JkePrsdonz^eR z6U-V|Aqr5_AbN|-7<){wtw*f`A= z7dO>-gDm!wVY6190-J;YY><374K}}t?af5FxPz{I?;ZmSO9xS59LCXwscqB-g|P#y zFfQ~cj2&QwUF2Zw04r>jgROP2_dD244tAS^-R@uyJJ_QR_8SL#$-zRXeVUgE#ufI? zaxmUota)LhsCeUz>tMA`V;fGu_;>#!K}^TrhBQ*m!7Z^|jYwF=uRZzITgdjQCk^P6 z6XMJ-XM1V(x5ScpNn;{Hs$xdQNRw@eWitGji+g|m>$>#(90i}8kbg)1{+3uSe|E*~ z>G5EiIFO%gODwEL%+KPIZ&jwp!)fH45NCEdn@f{ziG}rv-(LP$4H6I1nW1w+RVY)H zc~p~cDU}q+c4>rtIyDwjZULT!G#f~AVP=DYB$r`6Y#_;{ntwJBU3B5gZUad!%>2SY zl8ZO2!D?*k$EHEfOoOl%TQkmU!<$`n;eFPLRU<3gb;xG)Xt3GeWJ_nG$~v~phT!Y! zXF_n$2e*UY zmF0?^T(Pbmo+p~e3W6UfV009A<8kX2;F9c2c=}D_?W+67#ujoWcuD` z;IkKa523B6$(BFLwEqFl$(RkJVMWXo-|O%=3pl5ea4^h5ruz5Ucn-??E+q7N6*A2RuDoSV?vb+5lxqdXXemMM+qvdy;6xkXe9$gbh? zh^eET+1nBC>gerUReDkB^sep=qMz|3ko}RWu%XzWPOSJXyIR{U2 zZg~aXtZ9a0Iv!9&%m>gLZNly_k?oXQagsJ4#-KU?JIBolF}rG#^I^#e=tEeUo#m1+-8H15NigI732DxU zv8$%tu#s10IUlBLuWKsYx~tX3u>&b>$8!>9u1R`pl5=+>PedKinky%wxaiB=ATRDP z(mb0gY?jw%JS4ImWpI{>g>Vw=vtdtz&GJNsWp?QdxHB)beh)tM&G#NRuCVu02m6_W zg~2(BH_5odyg1Upcm|!mVO}d}V08|*(!o|c*gG8T-40d;Zq_uo8CK&vfJIe=p&?z^ zZCs6~F2L&?70^t;V|(5pQA%5yaBb;HRrC5FE`Rjx?aAup;1IC3rGTsQ(p%2o{EAgkFp(l^yYfh5T3e}j5iZ;(!zI1;oQ zWCW0tgXBmQwQwXk_N`o04Y24|2#H95bgVQi;?tPz{j(^in*577b`gfPKuxl-O130_ z^{c8=@Z}@3!XYe-Feus-->NEJf^5Zd2v$F?&9iLIht2YtXV~gYxHB)Tei%OV%@_5w zbcN;0DusQ=_=de-IJ{pw7@H);<4!aUJJ-Q3a4@@^n(sa0V25jAl^ww{b_7#bQne>Y zX;O;EzmgiqdumVcdO)n<{1EG4sR6Jj$dVwplGh>EQv7>BZU6e|{DA*A;qPBRogMH$ zPO5=U`myz73mj|{m?!3eeOR)cn&A4W?J3%6Wq+MZT|iyndUKMvM3=b^rY@kCyKs3n z6Q&o){3kn_2ei{6bpds*OTvApN#b}Ual{u;_uC_V2Sk6cN2-M<6d7?BAS*R-xm9An z`zl6U8qLsMrEoxHcZNJe;lL6;*FeGbvL=erimZvwgiW3*gUyVcg(ve`C}XE@zFhlF zS6I|$D2#nng`Hzu`O-&K*u@UUKB~gF@lV69bFl3W_CW{R;b5P0up7lcYN2e<|E}NL|YZuAR;%LqbFMALKba#f-G>d7{BV zb;od$rZNrEY9PsV&wc|5yHK|nNOIltD+ZEW_k7GiCb>|*HIU@GC!11ap-fPG(x{w0Ry)-ZCzC z9@z3GPUOw0oR7sLYxcLkId}eC-}>f6k0Q55LrMM)}Oz! zHfQ>*y2U3are1N;broSfMfMD3(qTD8X1{6~zRE6wSeSgNo+dk(^HYbi+@PnW%5h26 zd8J$eIh=91)r|5AcNppr4xk0Injv~OmtT&1jSu~Ubfutt&fFsqS2C+}58ql(GOHP) z2gs0ct}AU0r8r2T9@T z;~K|rk3M7$p+!rE?l1U#;k&)N`57wQ-zq9{NjF z;d`zJ+~`GH?J=6|(LF7?_qg!ujV}(}UsU+@=u43s8ehEkS9v)P;pOEU8eg*R-`~*q zvUR_5L*wtQ`_&s7U$O2#+|c-{xNm6u18lGHwV?-h4*huF(5|Yj`!?O!I|2FV8ybEv ze|P`c$t-M--k@KE9BlnV|D;6(Xuj})cv)Sg{>ZaEfd^Embc1g6t1BN(j_UW|3%y6! z%&>2jD|5aS{w3Z!@n0;iaUi6+O5jr8X>f5cS>m1NT+~X7fFUyGD+&F)D1gg_()%k4L*C{F4T$8tocF$%((@*#{Pj8qJdXR?m;0JOh#R zSA5MIV`vC*U_VD9gaUXT@!KOB?=BYQl29)x=K?1K_5G4!2R9WzypVzO&~c)A5fVK`IQ?4u5LtAlZVMC1D>2YbN59(J&Q zcd(}&jPoNJHf&sB?^p*r!NG2Wit}HyY7IC-Vp7TW2jRhxEgl{OgVCeO#-ru}XH{3Y5eNoYj$F^->iy*@< zA?2KhwzrlJ?JO-UDwtYW6k1vMyN3#kB1MJ81@jAw8Y-R>K=Gx|F@`6Gg+y%64_jkC zyp{A$Ht9Qe4h!vvzQ1pqcnw7dtA-w|8WN&Z4ehQP+Et~+qXoA0;llSl@t1x3dXGXD z3x^(nbNH&kVJSuyYvJ{IAaw?6l9WH#y07qhmhRBL(!%%L2gmlNecNj<`fSeQ3trrm z56UlisBq{DgxBoL*$r6Ug6|a$-AZ=YJ^c94bEj^9*X=VN8s0Tyx6*XmRx-}^rlR2o zXY3yS7Rju|IlOE5Q!J+$4-S8gDBHHK!v9JX*7b-CeW#+@V{YF*{#X!w0_-Wz1^)Lvb?@ng4kE&Q^Zk$Yq;u-Nx0X|W??imMxjKOO|lq+U8C@28sfCC zLLGU2YM;!7|_c=Zw9>_^pBudfUW~Y*h)9@8VK49 zl-HMlUIofpz8dsO&}%^Ffero4r<{q{9`lu@|P&4Z&sPX=Xq*e{ZA)+Wo^K)y3dU!wJ{jd?82AsCD%D19F56vg-u zY%ngznQ*y^U7^?z#YQMLO0nsR-KyAKiru5w|0wo*#rPtz$@h81UR7+1V(%;Vkz#zU z(ZuCzjiwwe6+2n6a}~=}te0Yb#Re;OwPM#RR-qU_Y-jSVQEZ`Nixs00Y{IQj>~+Qd zrr3vyeX5uXwQHBn_Ia!n#hNLWt5{#fZcyw-#eS{W?TX!_*zXjx(DQPPOSIx`A0A%d zs6J78b{+8Ol6Zxtr$M;BgY)htmylRMqCf#<{?!%Yz_&|=lU6w%90$Gj@a3nXqkXTdGa0W1gUY$Kt?J@ixJ>T4ME z0Jd{t-RJ-k#(qm8EDUA{Fd@KM55omEM9Z8(6v8eZgPpOtBn*dvFoa3YwbLbulQ(bj z^D(PmIuWmD;5$I0iwegS6^xD>UQ{eBD=3oZX=y-bMJw$5EU zrG?y&t+r)#$_QI+YbdL251@7(Den7alZ7rn2$69TZr*zyrnE~L)YOM75_TO0u)0+&yQSoD? z$J+rr48zgIN{{^g7U9M*AvlLW)Y!4C-aUdOPV{+@j@tg`R_7XFe`T(D6iwYau?Mw@#Yd&vrhcmL^8$AXBV#0)JrwJ)&JHi&B`<|a!hA76(i!2 zP7!mVWX45pFLqQawEuxK!cO2QT50wc1KopPM%Z1ay|G_tW8=Uo=|%gJ?ZuF?*pFnz z>;t9G9I!*5$6AX223uzP>N-V?^8lgQ11Cp-cz83;?sX13qKWM^`fwP=A?GZ&n+%An z>*@W!?-VicFFS5wBUQ2tD1u0u55h*$^chLhXHF3_80WDJw!`)%TDugJmA_-s$Z<&H zNT-O!shsQ5$gur3N1>BPqmg)esRUbxy@JsUn2{5GMo#n@jWifF(qJcUvmS@)NOx?O zr_&l^Z?fY+7kRiyU6v=?1zC!HxCqD1$iqeII;6zm=Z%YIt~=a9^A1`N81PneprlCa22&->+oK$t^i?5SXU6cKRE0#3Rr+$v$})~ zz_cH;06TZ2Bw;k<%tA5muFc-@Lw4+~GcfS(MZEX%ynkG+w#=*;8?Nl4{<7mr zcAL?Njd=ULtGxXl+AgGwu3iTEg#XzjFp9z3u(SOeSVv6?D&l46|| zj7v_OiB7b*uZ3 zceNcm+3a0xzwEpEKd|pA+~|q5?`kzVkt6N9YJ^VVNc*nF%Y8ie!^PTnW$x3OH+KE! z=uo21fe7Dsb?`@xqF**%{j%|jbGRJ7jQc;j@v1JPa-LHzP}8skh}y{?z0K;sapM*E z-hsCg1;2?DvY%5H`Hf5H{hqDE5|OA1U^kVsRMNOx*gm4||{# zYpz&t#ri2WSut+hF!|o5SWvNh6}w+C7v=`c-m7}H4-YW#nY~v$5{5pkfWc?@TW0%C zY}+jD^~+F9S13~ z5wn)Xi)j(aiQRh@KA^-|k0Ixuy7vlGQLz`!j&S2RY`^N5+0FT!u&luS*xDO*Uv)K0 zbzFNhyRQ~v?aDC~Vy(R$&F-r=p@>Jj`|6e`<&U-Y#--HnqQb>md*kjVHu3lHqvNt( ztld(4Ligh4X$$}dc4MyParaewgz0Cm<#OpSR(iZ$PgfUzcO%?HdkxXy4|Q-X zyRRNaHYfUQb9>P^GwV2PzdE{gJa4miyAJd1d%5pdV>kcn*E#Q)b-WiT)8o1O3hQ{0 z+pkc>|JeSk$TgeqG1O3FW3Aa#13%GgHb=h$tB|z-M{Zf0+#`FWBS#N#5EU1DzYEq) zf6|8>X&q2GjvO`EF8eONEXoOxquPO0h=6pCoX5j| zq$5ZFt#YnYBg1yTwEod;fk&f}cqpwTkBvatX>UD*k@ z`&XDS&i`2HB|s1}5H2v;gh~O4mEK_Bz9~*hhQ>;789Ibn2-nqq=@yW(T+Z` zd*TYlPb$dD$e&VD(z$p-`MHxO6&){InjbstX*EjW_auyqJVo2K-JPuSnRR|~N$L2a zlA;Oa1?9yPC*VMj1c@IzW>jE)REXmz%F#JHzg!ML>xRn6&o9A=To~69=iw*GuJ^yZd(D#h-qt(UFFA0A5caS=x z=_R|mOz*YtozMQ=b4knPJ6}8fA@rj(+>%|3?;Ul;^7wzf_uRv65B+Y=tcNW*W;PpT zqiYPw(Q!Ip0^0V4pltgSZGR#BuTvl3PQ!06epA@z9piIa@r1(h6(fs=npe>9*{0$f z3d(UwwS~U{JLT9I+=UplHo4uum-N+wP?9x^B?7>_fQj-A1X&SGeE z(WAN@)8iE$t5O^}uZqkQRf>x2x+Q%=J|u-k^YcDbhUpCbz}C-8$@yki*muB=^_azo z;~xiQ;`3M|rr=aa`zu+QY5Xvj*((gZ4FZI19L`KL8;21GU(w<}-qbzAox3`x4(gua z&Rvh+xsY9s$AORLd_+x3dB-~sKmRmIlekJD;;p`K&@aD&uGoWLqP5xfneCdf=9vNr zaiZs$kcB!9E%hxvwQ~S5PmUZq$gdYaTJIPdw3ts zh!LkE@>$_*{OZeD=V!u~%G1r{V+^VCwSsnn<>CKX;=2m}+la3i|I@`MY!3*rjq|Vq z{*^(0a-u(#$5obJ6!f<~RM95jUl#PI1^mmE?;8IyeCZwsSK8$;WkMka9;#RwqX-#N zgz$46LnY`8UQ7x4!pBG5R35xx^F0zi!#6E0!}q}8yHz_9sy@N_mhppwg%n71fUF+VVPd0^Ts@664ZN~*f4 z1s>XF9AdS5Z`}(;@Ft&9b89W~^d=8Uh6HM6n2Wv;#L}8uE9K6m83F&2ni;$pY2bgFoP3P?MX3yStglYR0+41o?<@ zzD1nJlaZ>o-3m)c^#X}Cr=}NUea=982jkxs#$StYi#H>HH(hw~wtFr|Vm+Q=(nu3B zx0XTLRS&=cECK(b;E-%zZDQXvWHp@k(;sINqr4Ng;8%;^)~ee0QQi?-z3FTy$Y{b# zRm^Y1OZdI*H4m|)yl<|>@8tjzN`E~tBzu&1>_%_;``+{w%x5Lr7lLp0rmsO^N+qKe zyCkEruj9sQZ+Z=j?rm4IO>Wk(q`2ZyO}IzN;c9@nx6E9nnR`Y;bC>a6yP9MJnnKRa zk*hZ$5le1Y50|J9ERd_mHw&42hly%2aJ%YVxcc%mIn@p9*YaNabHh!t5+vP3PhUOC zdvJ|6ed8!^+2)q`x4Qw35PLis zVo=DDY;1rWMFvLH)R=t@fDIRctRP|9yIA&iatXDyQ6xbbS2JUcA~hDutyFV!w5r<3 zT9{{cUsL;bBk@`$lU_pt1Qk?m@*$6c+9jqQeoY12gGdyrH+^nMwv?O6qMe{dd8xOe z!8_kT#LeDza|cLn)h6OW$qMPSRZIS1g58f8wot1LkI;b?!^48@r~Dt!FtUOUh-Mki zwtCyyH;j_*WgUEgAF7!0N6+)X9l}bK9#cvP20gCM5ieE#xdjq*I}1bEQ3H2MhXIO= zt4mGLb;wm}#psBNd4*+CMRAxpQWV5)L=@~d6zp?s&L(pf1*tu^E5u_cm}$qtBkv>V z3kXWi?Jk4Lxrf3reO^1e>wCbIh%%6>Ld5lu15s1QMxj|4a3~~wt|=Po1^pk3f&P!u zK;oN2GLn80wQJ(A+u8$xi|BWvOP8P~AytxXQZlHU^tcGje!|3f1-hPrtPm01R!u2F zR&95At8e_4**{)s%KZ2plEUI-A@89ui<5=FnjAsi1X42`NYK9=oMxC<)x$x9gXaXN zE#Z)bq3LsP`pdzJ1@NH_VN^=Cs{9L*M|sC%Oxub6yyP8kN<(jQTyXFrZ~7)&?*NYe zV?5d1#SS>7l{dLT)ds{lxVTob*|{+=ZHYIfaj;?;R6EV^Q{`XAAg_6o>jx{AR{59W zYUlPU|B_^|w@s@4VD$ioP3aJdd$X{r0%chxH%F*BX{NvttfmDZ(`1?nQQWo)4qgK3E-;BNrs^0uy(ty3%!raD zxh%PALz;j~A?al%f{ZItvUD+Rz^@rbQqGoIe7si5%G&r!>YTC_VP=4%2oXo{n-Q3{ z0Q_bIry;XVQscHJq>$slG>Efghj3#H+7lcM4KOBHx-r4hSBO4Pp=R6C55fRV7t3tM z2DUL6q*YrE&G0YcL(>fZ0wL>ZmCo=lf>%Em5*UYK5-sB0%&(iFJP3%n` z1))#RKz}!YZH}kjn!XL=W26oAnrIxy)zW|84S^$o^rP&~_OsVxa{_X36B2;E2>A6- z|HagC|8;LV(xHL1%kCt~zGjcU7e64SYr5g?tKM|9=d#z??e1j{jYhf?M(NA6hne-O zUYOdV!5;#8;ZlU##{uef@Un9oejieWM3E1^>rHLl!T~A$2oVmxBbJ5{!Y+;{8}NheQF?$9*z8Sz z2hp~$@G`!>kGtG(J1fqVRLY?osAtAJK;xpOE=-1+u9qx~*H_@;0EW84=|ueF>h@H@f+zv+9EpNnGEWO|w^zz|?aBmnQ}LW(S9)RjqMVxN^|`t5)X(fcTeJ)#e0- zq@i!9+E9x|jD7&U0U9)0^VILRpJ+?d zx8j0ru5^ps`vgAr)}{aG7MS*m53>&M2K^WZr~BUoDCrg<%JgX)0~Mla;#?N<9SZKLT7L-BJ5`&J z#hjY>%wWZGc!K`4k5UV1!*7^v{7YS91f#LOrg%f5x_;e+h)P3n2YVA$1rk zNw5&pf*bDZ{(5lm{IVBtm^tUu=9E2;X(%MiJA-FWzM!mLcmJ$OUBOEG^);zI!9e?0 zzii+=H3y8&xjjCvUsl|#cuy{Qkr+(uQzkZxiM@|_p((=z%(vzHHeI(J#pDtC!H=(9 zdosLc&X6w^WZ~NF2<{4oJ?G`1>K9EaWkBynxYA^%#uH1YI)Hl%)RzZX^GVF7Cn|=PnUzM zEo(lkfqoKiXOlKKJ^O={#n$2`4XkIHG{c^*Uh-uU770uHDc$3iB`j$48D51Yj*oe8 z+SYnD`Gb0IdYpr%$*yrO?8*1bx!Va2WOZ&j4teZA*BUxRx0i>a2w7~G=viM07PGVcu=S@z5 ztRE77%sX|naj%!$+u!7D+fhpW>MkUkki49x7A`LyR?giFmUUwnEJO54`5nAlq~^OI^Ij?Q zalKHcYHx7WgII|@0IVl-w+dYzR3hU&h^s#n!YLcPeh9uc4SC%bM{XOX7y!fAQM?vN zt)8czbze$6mUfhh42gU{qKyzHSQCbcuA&*6>iMh@_1IF$#2BV;y;eWVnptlHUWRcP zVIjEs;xK{+1lLE>S_mKa4OrHLaSrqIAx+b|%az$Xew^7%$$*(%ClWFYkoi+2!wzzv z5-h{dvZl*586PY6Q>95za>In7KS7%DRv*_{R)wpLgk6Ap+eFgMmHA!3(2=(3^*3k8@a>5j)|2uuxdG9y+Eu(Pz)Ak%abEET_zV_7Tej4e$52v8iLp+BYK9tAeCZrEj zL(KeE>c7;TWaXiy^hzN!3k0jIA8(ZiBNXi(5$&lWJ}P0nEXz?zogz*wD;}L8;v}Qz zN`q_fY2vy*fqL~I#ObuEGpuU&I(J;W!*C@;O8vpf#!X&=0{j53e?)WKR)-dPBT9plmmL;4o6=T_ zl-$G*7PG+OdbF{q2tJVyxisI{Xsiiv0^~K}XmpeLNFaa&PDU9+m2zVz>8_;$L>mg~ zQ5)J@AICcl^N+&8%61S*U2^Y z+ceG)lMCt)3%ft+ei}4uqwv<>9a-^NT5ui#&+W^O6 zn@7ufUb^nzNi{A2kB%l6S&JJk@-%k$X*^ro9p`IurR@7s+9B=cNc+*lYbDhCeJFuL z1-=8d@|iFmQ|=OqSBH z*`!N*?IqW&nJesO6H@J|&@!qqbC@K3Qa$AGne;(yNTVc$8Bi26aje!ooa~f8;zhT51*9tED21OXXD2Y7}8Fo9Fj$_e{Rs*njiON zTqA2${1eiTEx^53L>^l(*qcEwR8h^fK@G2?k%lqD?UqKPc&?3Q-KiC`P_BQK(8%&6 zIGyJwBE!yVbCAh=kz;p>w-DDaNQuva!EI#yJ7~~siRV_vD$$sn)*5byI1dRNIm7Rt z9XHxSe$+m=v70i;_uBdB>6ChkD8`wh z&1`^tpWU+VsMiWz{+-qb@i(IUWSY&Ui%969xUJS7wLYGaf-F)+dO#U$txuE7q7;Qn z@=wppakn+TNV|Tna)c{WY(+ArBo+A2QVR>ASmCDK$0;=J&W(GoL8fPhdrPB(q4dE+ zwv;WdNf#(y8}P6)vI{gO37dSGDBjArrq*v%Jw}P*C95zxN(<@|7jM1mqA%m1S3$|zn3a+D78TeUnpUW#Hl6$$#gaPk8u))YI3pEm?y%T z$`UzH;dnv-OoxQ?QKMt5`|xq71gp%oQ4P>mA_JojOs${Dv6U$70$e{R#d-vvb4sxO zgiS$)Q)k$2CD$CrjS@D{hRxNKSoIfWP??rOMt2G$p`n{gQ1t}MY%&TJG>}Sy3JPz) zAv5ddM?27**#Mri1TrI*s;LQH$16X;hc0GZyORI>Zz?zL;lnYSj-> zTD1*YwH7#Ru_jBPRdbCD$kyo3l<4UJ+y$lZPJrncF`RKJ!K?$XYLUm(Js%!C9yATrg33?nVks406@ zM@>(+wl{3&3AkTsR6jnvQbMEKsUn0f4YRGSViZs?>!lo5fk!hrLG|Ek@#snQ`JNSa zpEQ_`Qnm%SUMXpr#zP~)aA8a*HXc)9p~r*LqpGlMZ3h;@A4EQQ0jWs|D(D(i&{vWD za>$;(OvE(Z)zrF5yU^1_$A<~Steoj`T`rp@8*SrTP^wUIEUU#66P5NS?BAK6DGb%RLrut!LC%|@5G7JiY4^Is{aqo`gK z_2H-7WiGjSiqeXQdUdLKA^iV|u<))ojWW(Z+pj7i;< zli}dRQKxXrE?k{L2Jk9oh=W9!BZbpKIOs2&QsRjs;b{#xWcXZJ()TU|zC#rFE@|J6 z3`*kUnMO=TiDWisxPHJCp?RtQS>$8+!L9huBYeI}6v>L?!M=o4PifsZdw@yreKQzJ=8{KCIj!YpJ(zJ>8XR4Z>H?L!t{69Mj%#|BjYS zs9~QfNt7aqp5aV{%Dq@psKtjm=7bABR6ErYU| z_rNae4&kmJuASN)SzKUGosyAHC48Ezzg3~!R|_^AGBYw_&z&g?P$moqnOTzW4HCvN zDZi1tej_vBcj6F{6qKLOn$l$D-ueb-z$RYn-X(J^G#m_nqoerC(vc=t^0^F6{{zfC zcF;jESNQ2IJX3&I3eR7{fS4+A$@BRVmlL3kah#oL7v%jf!pp5;<#YIGA134i(-v99 zXG=nD@Oj#OwqWu8p=1~mP(KONFf4%)AsuNYH%~*C^G$ewP!9biz*KaUdnE^2FGe)@ zu4hEmWs3RAs%tE9CdV~H&zWt#VYPO7RXi^UcjXe6;`zH2xu+Q6U93&`R%qzS`3y;? z85-qxk~c-vRpQs!*A6f3AzEWD@Ts}fuF|pb7r7mrqn(4Va)*y_BSM|y_Y$!sdVu|5 z(kKXZTu({>zbggZgfp-|EnKE3hc8GN^9aUwY56j+8AQ1*_kyU$uVhSd?waRHF6^z5 zyWvA@f$0-j*}s#7bDXnof1Vx@nwWl9BA8~$z}qBnkMQD# zvMC9Z z9wc|WM%*=H5BWM@?&jdlw38!BlPCD4ky(an<0`p*e&p?td>)nCkyU916mm3M?w%bP z*)&bEG)-<_ZneS0x??x9#+*i<6ZfUHs{TXPlm_QU6v{}G@|r6tWP~+^Fl%BsU%9g% zAlMj3%eremWcOQC8S`{xy-YoAolFthfR>XS} z_HZlWTEQc&2$OFeR>VsZA<~N2Yu6MRr^)h92~&p^@vPiDf)%kt0!)gqA`DA)TMWx(Qvaw2pJ7>mKm0k!dMO& z4doIz(r8#H*pZEf1|p`LZKGkO*7b#kTWtz)!f7jQhHRRx1$#EaU>GFvLI#6l@K?$1 zrw6dHFc+PK>6>UsnEH+!eavXdPUJG-&KEIsn30QjdGI#(0P#^(%>pR_N3K%2yUf0J z*?X{i|cisOtc zXMvsq`Zv&1LEiyQ15HGv(?B`5#IOqt_0#L3^j|IIObUY~6RZ;fJMW7QwS;N>pR{1n2M$JktOWpwbGU#N` z*FbLs{SfqKP_B_r2mKoK7SL}&Zv{=jT+B>R&T0M{^kmT6Ku-g`9rPT~*`PdX=Qp4i zg8mk?Kj>Yc*MQCeK^b9xuHdluP1IgC;;{{tTJ~`Yb4q zy

%6{F`t&jI}_Xa?vS(C(n?K)G*mJ?H??4WNTSUjn@r^c7Gpg}n+o9`rTPQqV1+ zlR@7E<=W0$ptC{$4tfXZJD?AOz6-h#^nK8$KtBNeGw4U4FMxgmx)Jm<(4CY*Fn%3poc(b zgT}eQA80%%7iQ~&J_*_Yl<#ACKwkt+0(}MaY|zsBSeFBx1lj?#8nh!Qzt5fpdOs+Z zoh!Ml+8J~iXcy4spyz?E0qp_G{TMw#{|$az(O!+ zDrkSulR)v+rOFJ@%Rsw>;@eA=d7y(px#l?-bR;N_z^}X&^cv84phH2qif|q1BcS=9 zkAsc?T?;xAl$#?)fqn!!8uV*WeEy{J8g!UmP_9TOgKhvt7hIW#{;etKHqhpvt3BwC zKtBXc1KkOF8fZH_3ui(8cc7o@j^8Kf7r3nuq>|4&P~*y*K~epcm7oxNC7+YMp!b3{ z0p)B0y3k6_a;Adv*}OUEQcw(Om7MB01@uMGQ$aU@o(B3l=-HtE0`-A5NkScga$>Lx zC}$YEf^zcaJkYa1dw_DPDi?GBXm8L#pjU!E2zm|ZLQwW;kAV&aeG>FK(5FDzr*WEP z6zFEq(V%aF7K3uOV?5|TKubVB1)Tu;FVIrZ-JoTl2SCx^SGL3>`gG9Nptpdw1+Bzi zN6=eAeW164a^5ZodM)VPpcSBVK&OJv2fZ509^?B80cR>cY>}0ZQIzg zo&%i(`aI}UpzA<6)$;=AM$q-3FM)0VeHrvs&~HFlpBbp%3-F7NLp`DbiKT$Dj!y<< z9iIluI;IJOXq8<+F_2c$_+wr3*^_lmQ>qzgf6$XaX`$PbK>4`Fy5@5q>zbxDHsV)q0EHe_@GXDC_z)&>5g_fCfPMRK>df4)iY2W)K?dx+UoSpgvI6bq?r5p#4Bu*O!1k4LTn5 z&!D$~t^~aY^cm1~psedtApF0A4g=-&o%Z$f_Vugw^;`D!NA`6hDvRNpfvy3ior8L3 zJGIUL))yGmSx%oZ$K#%bEAxSJ`aB$6{npPdXV)rUWE6L=`6ZB2EzbN)s z#a>hF4aL4u>^sHK6Wi&b@3qrwuUJRL`YCpaV%I8`uh?yh1r>W(u|FvGSH-v$!j$6; z#s03?PQ~^r=0@{3GH77?Jl3xiJ5@1$K+A;dq8QIoHP|JJU8`8WV*HGV33roXLB)Qn z*fPbID^{!6I>p{pY^!416{8Kt+&tC+#lBaJmYCrs+4gy?PKtF?%&*u*ie0VPFvYG{ ztU|FFid8Fir($yzTdde4ian#)bBcYW*k_9EQS58Q@K%srw)(aYpL$WOxnid))>g5e zisdSHsbW_sHbSvciruK#bj5z7*j#SI=Vto}Gq8RO06ZZziZdB|Z#eS#Qql!JD*jtLdqu6JPeW6%=Si`0q z9^2=!e2R5Zte;|+C|0UixneUFo2A$s#pWrtNU^j9pD0Z7-LB;M@>>@(O*#pWnBPqF2StyFBgVmlN|!BdJ!ubJ)hSZ6BMPO)x^ov&D)VwWp6PO*uK z-J)2PV%+Is^5t_BeIAQXPzK{Ol)=_1wo$P+72B%V4#jpU#z!HO9^P-T(`%tvYsJzP zJ4dk|isdL)q*$?H6^cz&tXi>vVha^ptk??0o>A;Y#WpGSo?;&=hLse%Y zOvTPute0X1iWMn#yJEjl>_Nr;M=>tS7@6{!(B!*DvGt05pxDQX?N#g>#jqL9PLB(a zCcUPLah20xXDQZRF~4FLDORLdv0@d9O;wCfkfs~~#U4;>p<<6K_D985EB1n7Un#an zu{b;hnmp>;K96;dVi}6@>C%Mjqu3zDu2O7_Vtnp2a+#vo&5A8lY_Vd`DYja%*A@Gl zV!IXFuUIQQl^Xu|JZthjTd@v`ou^n&#ja3nh+-oY8>Lv8VmByuyJEjlY`J196$!f6`QNreTqGz z*yD;lqu6tb{avwtDE6gdI~Ds*u|tY^Fa*e1pPt=JEWosMZNQ?|CY&tr8~>^#N#Dt57ALlnD4 zvB`?vq*zd~-zs*$Vh<_ym|{;V_E*K$D)xzD+ZAiv+$jf6Zm@N&tzu^@)>*Oh6zi+l z#flA4>>9-;C|0J}JjLcKwnVX|img;^m13I}dsDIPitSJ=0aJ{oj*@Jj$2woJUW$!X zY=UC9DHc@h3B~@T*c!#wEB2OR?*=V!!)n?Vpl45tzuIZo2FQe zVs|R`sA5kj_OfEHDYiqgU5Yir(xl-p#r9#Zuwp*N1}HX2vFjD9Q0y+n?on*HVk;GU zOR;wpJD}M2inVOz@OQH9^H}W^J6Ey3ie0SOHHuxQ*iDMvqF7L|-zv65v89TwRBV-E zuPC-zv3C{Qrr5s~`$4f*zjDfUitWR5nPORrU8dMT#qt#^RBWPRlN6h$*nGv7D7I9w zm5QxWY^!4LDz-zhU5asO+~`oe?ekd4ilr*nMzM6oaun;M*j0)RRcwl4H!F6BVsjK* zpx7eCmMgYWu~!t^tk^ciK2huk#jyWbO6jpuY+s_)OtI4xJ5#ZqisdSnuUMgClN6h* z*xicVtJsr@J*C)R72~m1tObwt55+!EY^P#-6+5ID-o>@!Hnn|;)=7%BSFEFA{S_Oa zScziSD>g&1YQ^qUY_4KYD)y9On-qIpu`d++O0k2A#hvPuqlxWHw3;i{Q8Axl7bweE-HczpoiY-%Ym14Duy{Xt%#kMQ9LoqAOlqk`Pw|yS#6va+gtcPMb zie01Fb&5?;tW2>Q#qLz>F~y!#?5~QgRqQ>*K2+>`#kiPjbh4H0OSDc=teaxzD|V$~ z*D6+_*i^-86uVQgrHU<6>}ADXQ|xoa{-s#L>5iO}Y@f$UQ>=|*7b|wDVxtusr`Tl0 zZc=QHV)GPRqS#W!UQ}$8Vs9(4s_N`*|&v44&v3;12RqPbS&Q`30V*M1mM6of7 zjaTeu#VQqhK(U32J+9av6?;yx)rx(l*cXa@t=PAU)o-I^vwa@xbj8{#)>*Oh6uU;T z>l7QS*aXFY>Q%_DfWe8-zs)cu_k9aWovHxJXTx9&Q`3q zV*M1mQn70l8?D$l#bzotOR>d@J)+n%ian>;+lsxX*nY+StysObPB|LdK96;pVrMGW zNwIE<`4ziJv8xpurr7n0RVa3sV)rPvTCo=tdtb4S6x*ZN*NVlV+cGvyecOlUTE)&# z%%@lv#ri3BiDDxa8>3jcVp9~mQ?a>iwlVTq#_NijK72B^^y>zE+4Q-#t zYN^=Cie)O+NwJF*%TsK$V&fF6RxF^{!;1Yuv8NRKvtnBmdrPs86#GmuZXZFRu=W&h z`#jbz#r7$Nuloe^l7fR1g04Vri(s$#K<+vCwhvBAjrYCyWn3^JaB&(g>IHJMhpi3f z;5KMH65fv=TBy2CwhuGg;<(t1KZ{{^<5%M1cBRN8KN*K%eE99bw25)%$j|)Z8zvQ% zSCq<@UhZu*M}2ZTJVQ2=u;*ZRjXBPe*%;@-#^OG*BbK|Pxd+x|72kk>=6uTf66#mj zeiNsW6P&mR%E&B3vPLePSTUizs0_2&=JZZHzrwZD*iMO=5o04qZ2k#t2IhAOlicTW zhwou<9Cnvon!?S#lIY?8Dw`nRMBU)a(@t@Qk8bakf+d>Wy-31gHEhf7RbgpT-c#^n zdHdUV7Phk3bx?`fZM-jt?RlUGTgm$E4B8&F3+TD_HS3GlEIE1wyu`s==rdbj=<`@r zirr@WJls@jhr3^~Rf^Rr_NHQ66+5UHwmeEISf;mqFl7~6rr2`DsOHddXgbt9Rn$B^ z*efBB+auU3DUh2H?3EnIZ5`~D8pur!_G%HxZ4>O(I*{9SLtN36(t-`S@e@X-`8MPx zWSu)=>W18;@}jhHv75nQFiGdARCF`gj(gcr&46)O1q1Qh9o-D@0p%mL1EbEDsWQfD z2chF>&2c=Ke6`z8e~stx>nJg+_NS?3QkYtfL*u$EWe?Jrg`eYCPO2Z(>}DH04Qj-) z!$=eLI|G#J2i2>@WPpXivoZ}7Dpg6fLZ4Q74rn?kR9AM%bp<^e*F8a@s+E3FgsJQg z3YD#-TswfWOi0gGSNe>)(&yp+X}OyyJR5ADV)JdEhkFX`aJ7nUR*Z^k;-*9SOdi;2 zYh$dP{rHW<&vDno(+5A6nvNRN43uHfb8wGl#C`6KiI=-3+<>V2n;Fs8KX$y_+nyPv zamiH26;_@W62 z+FOoYW}p`QXXR=1SUMNdRmL@ad#G-`U{zdeJwc>ty%5 zO5U5e1}B)9*2aN{=S@3rUG!mK+l4r^W;8*bp|>um?Yv776=Gkn>5`$nrr5mATsizq z027Jwb}Fyf1QUe`vPGuq=&V^sQ}AOh)MUC#EbK`Hy%ZFW!8icGbk5N5%5JzG1eyyv z81!<`A)u_|t3j##lw<>oT1{V~MXjdK!(Ea#wpOt>6#Khk?1W8RcETnuJ7I&d6E+xj ziQ5?Vhuau-X4@F{WZPJqI0s9&eS8<$w36_eV1F?Hzcl>l*h(-(BVkEV(un)#)&n4S zjrmc9)VoHt0;b8hX5~2|iG@lw2DZvOq#w%C~TG zV5p^~*`b`4)&|$HTUrXTX-AbnHul-=EYvbI!f<1V-)l~) zk4>MKqS=H@CxP9kC%NnMPIJ5;MJaQPjBd5m4abFQ;>fKwe8eh|HcUn-6p?axtDPWL z7sbKbkQi^W)M87NhSn$|#aqc2g$VER0KXGiWP@@*aQ zdHCLqjXkf}`-**}*jI|NY$iSS4JHq~jbdXwirHY9is9W38@pPu>5AQ|*zXm4RIyLc zqD^|+ZJ!7E8;3yRa6=qA3voI4Ky_({;*rl3#Jl+7r`yUIRa8*kAtU2XmsM$y4kOEo z3d?VR@TuJhZ-JGYB<9qBrZEGRFq zA!@A~=SW1S!`qHVlg3#c%0kiD&ADAU_)nMLzVGd}ZxF@?+esL!LwV7Z@-`(<4)e)c zx9fWN8sOLb>Ya$?$P9+PxcXKaSH1yz35mhk=w<$1<6Ox zt^=T0%qv`me42B+4rJjiA-k#)By@Q0tX;RO6aLfnKl`b?!_#3af(%g+>{;nNho!@o z;C5kz6nF39&S=%q{4|m_y&T8d?Rz`dvJ>U7Fhy5LTF*oyz zOG?KVl@v`VFDNgbIKj#f8-yb+oDn&H(!`O)6(ub0jYVY>5vE}Lq=I~XTC%U5Nd(O_ z@-rei`T3KI3M;<)0XoNOyU{FZ=#z;aGTq|1!F%*cox%oi0b z%j%ew)j2yY1pi3cH{R1ex;U6+Uarss&|x%om+6jl&lUDM~uY_ zaXnJdPS6bb67@3$96}7uD=sXXIBDXj^0f3T+NE7qT3%dId?P+qpVk{gM)7#e{}{eG z7&f*NWD=@)LV4%x{Bm>>2`SysO7indGP8KPO@h3HUN))t#vD7MBjEkRW_5Qyf-qG#rhO^}LKj7!y)#JI3E?K$fq=O9? zf3r1!DZ?iv{QF{#;)*G+o3EpLTuYK=)_V1ocS}x!D+UXBLk74B@{Nj5@ zU9mj=U++ElaN9$_n=|WSJf0!nYuLXOo;S37;>7WjhL%j4I;nH^&@mHBiiVc3=7vrx zD;zq$c!cQ|qOOW36ppVLSv1tXSz1aSXMr?a3bu6vhw`N z=(?acCduQ-Elih^i4%?orzHjBaR^4;DTzR(Dcn#zsiI(f+NAP|k;M~-W@Th{K`~28 zDkh-A9C|~cRtCJ8*$_vEtWFH$2npRKln&CUJFlacZ@5^GPfcO$C@h_tKMCBKwha}; z6hZ%#uVAdOpSr7JG6rqK`h&?X#?C)NyE@ zV*kzrzn!c`DJP}EBQEw+60(ebI6BN;Y!8Ev>BLSU>d`97Sloxap}n>(IOF=J_s%%) zlGB=Y`pq|sKiPhtvAy_G^s(Ar5j+jG4fCNWmE+H+Pz$X#gEG?E6pbiNJ0GODG>zBU zY3pD>NZw~B-}OI}JaWu7Ir_4W zLyk80ojRX@v_htFA(_9*XL{_Rx-*yzvkMhA$Kl7tTj+!SmQO4T|sG`fBs9^KH7;h~v{?YsK>l$1+R< zLaZ71-x9x68D}{(rSgO&p3DPZDtzYd>F{w*FI7G#~?AW(fX**vw6QHzvO6^G&xlpa-hMcI!y&vzv#W~ zHJoZ$)(|XutJc9A999{WYNr}_XC^@4RPiWrQkGlz4R@+))uA-+t!v<^x%5y?pYtDf zzt(-%rY&l}F}Sw<1|!ozH5IMq z(&XU!_8WrFQOu@NgKL8iu%gA2rH*D*FQT2FZPzEvkuc4x!frZCZ0t znyHIE&6ZcKN%N)v4oVz^aM{&z(YEe?FMGk%iWa*2-zT*Mfx@@XW9#e64B2VPCE0Tl03~^}}bH=T7)clkExH#rC05nTC3i`grV$X|nN% zu^&HEOnBgE8czXrOtj(f{|Y~b<-{eIw8HOG-e$xw&A)Bb{ZDbfzWo5qbWV-B-v`%R zYM|qD8;=jnh+4EJPmD|Y7RD^&oJDKcQs5x8bA!9y$h|2+SJ&AtbNV$qCzirE7p5q4 zWjlkp?(cFIob6p4{HU?BfY=xN;YkWgQ?mvwU3MDuUu^GZSN64D9W0@AeI8D3})xa88II(o9o-QjB0QJpo%@Q#%oChaz;AzXKS=AxJMkQ5A5!QI}~+4_Cl<q(766n!5eg(nVfc&yx9_g^y13oR+C2fh#U< zsDw+^JX>j=2@;O~OrA#l%{HKhX3vW`XS9q^&NNjUhm1wJmp@DkZNQ|c)7&`C7MFAcx5@yo`qCw@*wPN5x!(EWum6dJM8n4CDnP#gGJBo=Ts$z_0Gm)mV=_-0O<4DGq?6^>kM2}?L zDn->xLuHzcQw+{jq)B3gzMbGeLQuUC(&X zT+k9w_H(76tOd3kGy2hIMnC#I7Hw67eQx_aVjmmq--beeD-?S{u@@EFt=N9WTB0URdMDdHk9CD& zLlpb9Vz(>Cqq|Mq-zoNc#U52`0a~pIx5)P4%VQ^O8yy!xP`oe~zWf2EVy;hyFMS{Z zgkgUZnGTcWJvvfsXbRg9M|<7v%7ZpEgm2PqXTey&g*Y?bar;_Y)P}hFxbJqc|KJ2t z(zQ*8gkrJRptHBpg)NdWtlPz9k~1U(Q)d2lNe2=n|85tTNV@S7&TKBDFOUDkrP*af zE4Q74Om_hAY~=8p2!#8lu=X7m3lAB1rr?8<*{E0FGLIeM2!lUj$03OmYq^f?T`?9e zoLyafN)7Wn_7%2Vl@*mv#2$*Wf(fIGWJA`dg5vQNWktG&jJqtH&0I($auZli_@1pF z-Ohy-?ap1hriI*(ul#khm$bQ}-9%RYPKMP=vC+j^`Qt9t2p41JZyu_-Db(RH);b*3 zDyNQ>zkk|cB%l*6Op%GF;a3PfuA(l(QMqER)Fq>;S0Ky_oI!zOI9aKSk={25bCSLC zhiEa=tHq7e5avVM7Vy@Q9?LhGPYYo#7JplDe;UFKZfpY9#a|QLz71jSv%}TJUkluL z7-9ZG#^BfxW0jZu>6S$&o#oyV$KSvmzDn(aUdK{omMwrWu)h)ZFCB4x0VTsS~&5rk7)7)S_h^ z%S!ALL?3&?R$}d!Gq~F`E8}M`#_k5M`0&87uEh2{iUr&wZF9wE2veHbwFqM^au4iJ z+*NqksxWsErlEXw?Hc?!tHwXJ#c&_;r5;d~V(kpPMDUrP-H^L#{Tpv)&FfHj|6jXr zGNVhf>+qd{w54P14CG8steuL#6a4UUZmpj{` zZM84_`Fx(x?Q}m|ivQc2DNo22NNzUhP*yOosGzKHO!z*Bh;0qr^l<*MZ)=F$$@otU z6YHSX=i+BpwdwQVd#*CG3Jh<-aE=vNceIU6_!9Xk7xDe?u6}Recq(o?|5w+RdqR+} zR+=mMtuF=>%T*t|%PYWG@8AlDx!V#xme8!8?}x7qevV6XJT@K1UI31RB1ea6{07Ug z43F*7YWDkVFUa`Y@ zxa$BL3KrtpI#iL0Z302iq(c=6hc;KOOC7eBCY6yoaz_X7kKrZX8fOp=Bl`JhbO;78XU zy1;AHb|vMEwj{dI7XH|0JJjF~?zKK(itC) zbx9Ykqnt0lAWD9W!+HkaR;J3Y4jsiy{b34PsB1W}71TLHs6@k2ag7TN6QL31xV@nt zYeaEm;HrNBY#Jb_i zJL{*Xty^coZ`vSzMz`qm$e3cVxwtmiGqx|0A9J&@PZZm(7{?S7m(yD&F4z4H)>W}5 z6?;lCuE3aZuP7!KPn(5EANq{0wza5qi=V93?33xzcl$x*5qN1@fx zM^zlj1PW=_e_XMh1=!7P|lh-zJ&(a1VtBc_+f^`_(BC_ok z(Fv4w+u3dr^qUqzpJ@^FnNi7L^KfmjRkknDs#WZtihZe=7n)__Hnn{oi|xQ*Jro@w6WZ+L-L5qJM^e`C+6Hg1 zFXiNY=tu|N!RzgS>7$DmU-*gIftjyK*H1_fIZ_3-kD-}ItdcSDO2-v zJ3%R;`DrL&w&K6TPhH0&&<0}c)t`RR_waQ1bnJF<8l0Tb)pb0A!_ONR&0KeQI*kz1 z?Rppg9e(WN5yIrmxp=pWdP064K6LAh!_%QuaO?vDq`*hl_%Qik>_Hf|BBoRD?3cmA z(_w74i__gsCz-6AIfHtF<*bCYL1?-pMIb71T&qJOaCkZv*I1D$Hj=E!JvPF_8BDC@ zHexCA!ePk!HWII4*ghR+(&-j~gs*OjE$(8O!h+b5$J>yEv2Mmy{*OG#)Nwz|zKk8B zu7qh=#g3s%e06ffrv|S3jht8_rfvR+3N8|w1->$zz*t;Tls~3mk~y6$zm9C`oNK8g ze5^&v*eo7t8vn3~osL;uv$};A7DMk8`ochX^=yZ3T{5%e7FQNit$*NbhtK=TrbVgT zSSyR!v<$*sjFrVjXy>v#&6W>G^~$MZW${;b7zwE1Lg&*EXJh2oz4$dRIw~Spio!cI z;@9K%8p7o8SqqNcjjW)Bbr8fE?$-$O&5wk;8R7Wdt7q8rz_ELZmEH}&_an?W_C9cR zh2yss|9~*v>=_!CBi0JvX7nrt2$R`XlCw@iql&d6$8PSVOcTcWA1l3Wh<^dXo$528 zkbKPadINva4s)dRTBAafU`?dMf}pD_y}`J*#SS9@@h=vC^TFR)T`N-m1FL?gwuS(22tW&p`#OfK-L%V%51-nmEIJjSCfO`gawDID?Og1^CZH! z(KhI~V9E5*bdF`E^7n{-!rtk|VITO*%8>UPkI&g74NyIuvE=x@Gt60$eN}jt(S6c6 zSPf*nI$|8>wZ|0XRv!(=aFowu4u5PpGU~n5pSHqy_*o@`P`9zp9;p?4RKY2K-1zzv zo4?av zv=c5w{-@uyHm?(BWgfrRi9>1W>%>`jrTgc<${o#WjO6uo;;iHN@_3iy@!Ga|r(Kf* zqoz1rj)&k);$4r2knN=OW$fMP_7d>p`8ywAoLUDz=M|3TUF;bM*ZXMu91O)_2Sr_3 zJi(VW^opYKMFo?JhTf2wojG(8&!7uCOv;?egDehnG>^jH$tM3`9T@G|=HkQrVbzX4 z3*nD`Pdm|{T%IGZXRk6Z&T_^)wZ?B>4H;{hH=41^3UJ84f%faQ{#DMakyYz@$m@_1 zZ#2`^hG_;S&cgpp{8IT+lV`;n}FrvKTJpXuEKv#S*3EjxP(nLub2NfuP`YGK}Mu zb#lD?Cvr@F497X}8JQ1+&v1Mle1_u*@F~YLcD#wpFsAcb_-b*?KHhFm4OC~~%?rG@ zzdA7Y9QgRQdtlnUzzTWQxQ6c$d1q$hF|6v}7nFIuw{@fUV6FGI40wWZf$D5V&y6?l z9|v<20@Wi0NeWaC7f*7adZ>7i*Hz+a5vU#{p4Nft0pdvuRQDH8n?Uu2;zi z-Q*SUvi6hXaT>vy=B4hMyjAVrt{J?_yxu;`<9o6DYh^np$9G>}_IYsHyqaOF0?&zz zz6&6qY4glm)4>|y^EoL#-VdM4m$8E@$Wp*RGblm`_~!>j2m$}npa>!0Ul0@_1oD;# zYgoX5|Bj$YBapW;Si_PA{Ii21mO$RJU=52E@Xrd0d;)oMf_XCo{v{jaweVEb>X+`| zv_89eS5&IZ{zCq$wB{0 z_xjbV5oM*%KbuiDyYd#{{^0q+!7EpDwIiFLnE8`F2qN{$)r3 z(bpjQGM|4IqPzS{eHBX)&sDK3P%$T1vCOwC=%3^BFIrujyn1~Dmw#ozKL@$`RtNLu zNQ6bcyhW>5C%E!fiZE9CHZozbly?V2<9^BaHY9-ZBa1b`!OKjsfF-!!2n?GU7`%*3 z&9~W@9~eA4ICue}C6JMO4P~}ISTUc`cKO~4RLl=n;7)>jPw@Rf#S-&oyl*RuwPE$z z26n-gOThxeW>J(Ig432V`T^fJ0r*(9<-uXgeOvAGBZe(l?O)KK>T$lg7Z)5h(_7tL zju=QXdgWdnlmi%0UiThfZ?r20B+H^wzTOF{RqhSJxzsmbZ}gpz?*g~zn6Gy-)y#i~ zTQtqrJC!=-pY0Yk^Yv~)1@q5xi;nqvw^r?Pqwu}ab1k7}NHg^HZWEj~(><-yJ(urL zx@~Plf49;t&C}OAJveNc`vIf3=)aSESDoXVlHn`O_6_LjyRb)QQAQ71PD3MI|;=K^iD=;0=-jFh(PZa;62d0 zHEJx-I}Mx$z$4TIjQHn)m%xQRg3@aRO0$Ee6T9l1z?6)@fUY<=gQt|-0G5-g*4LUY z4(CEt)tWOP*w+P+$N{wT&sThR=+L$3OU^QVNgDc#*1;O~1MOEM(CzUFH5a*N^+L_e ztNO}Su`^iB-V+C61TM@7*06Yi3$rowyr`FL?_wU1fladKHAnN|7xbM7|`!Rf1Bcbs0 z`?z`E%=+zy?=nor^@w^empqXN(!bHH5;sF11tX90+h4K zuO#hBpkToO0ScxPAbn6;DA*PXhyf~C9#Tx-v?VRI4=5Ng5Tewiii(ODum~t>(5lso z7^UScL@W;lA!+x98bp+_%1+R#r?ZpG5r;B4m*f#!zSl>xu9)2s#kskN{aLgE> z*cADGc&cEh4B&Uc_Qe6;g2Hk5fW4x7@Tje-z&FE34ycX3Q!-)z7nevDo#0&?zC)!8 zRLDuBIvos4aEGVlJ7W4Uzwe55N_0@2V&A7u^rlrLk5-Q!gB)tn1yaB#Yi3>4P}Cy~ z==ARp1_wFA!=y0|#rf3AjzHXm@!~omrj(ou(uySJBxRnQ*9-`V$BDs6e7PhJ$D$)e z8D^M?3|9(P5@c9CLD~v4@VyK4EXBK_gt1sfVL|2}(c+?;TvUF;iu-GFPU~kyl~R)~ z6FnpO2a0sJ1geAx#;ve`czSE)*^_&|<-N6)v|0ToN5uCkDAr9AH<` znIg><5jvww@#+Sv=q4}-GLCoS43Ufv!cV^=CA9}7CGsvFop{L8V9#fy^gZ@e>R0E& z9$aW(Y9%Liy+X6DBq;JQSC}7`qVlk6!r08QnLCh4mq7WY;6=jZs(!>6Ez~sICMkk0 zpt-*x8gqSusg)eD@00X<(BZ|7nS74UB{J}plkv(#@0N3|FwRJRDd)eH)mzl57ms!E zFA~Oc;nYQ$;hB?)Sl}#V`k>%LLzf!sErHJ}&`eRu-FOLgb#z|lVXv!SNooJc6h~Ky ze|Gkx`#9JAXHt~vPFHza9FqD?t(-*pCH>aG{EH9w8oy2w4@GkrF2zkph8qQYwnX-u z6OWj?a`y6bv4p?Ya{M0L{sXenOEN~WZ+N%#Wn2_Od!ezy<$VLbk8!N9cj($S+BXgq zW*w zQY!;8Z^1jT^efux5s~+onK{vSrMB2?V*u9a3Mx-h*;}Y6%WOzzwKXI6k0kw$u>OV-@@y{K?>x>t|uXwRA-ilY+POjW7m;b;ko-HrN z$`1ut4ZH%YZ4|_R-VgqGKlsD_;1BkLV+b!;?j8N$-|Yv-Y_kBLAy<5*AU@!Vn~BG- z>(^E2YsZgC)#$(E5+Qd17`%)ny$vRASW{s1;S(`oNg)$h`MO99FX8yKnC~8wV>L=z zB4>!$5;9zzjNY|BetO9fZ>h&#jeVNGo4iFF5_CA?>q*{;ea!Gv@h$@$_iThGAjIre zRwbK_a30R*AY`{W7a{!+STkoE^AU0)y8t1(EOfceY`hB*-iQ!4(wjLLEk?+p@H~VZ z6&ew8dIX-$?5uDdxk4Da;O3toY)8nkWi7&9gdau7 z-s@us8xTUr=3gQF1j1d=jeHVeJ;JLIa@CN}AmmtaBSLmFHzQEz(&nkgtsEx8{yXw9*hvvi{?oP*CRX!;WrRABK#)8*z1Gr|`Ub|d_Uoo5CpT?xVmfe%86I&UsT zNcvq7{v6?Ggug&I3E{&Ck4N|jLeAA5Mab(`_(<~#gpVU+w+&xuZb#UFupE9e4nJMT zhcR8phq2PA*HX)5uBTX^V;BV_Z)sF+u`*n1##psuBOT+r^jgLQ$BuRE1jlAMHqWtT zj;(Zz-*zd#YaF}Dv0EJ5=-AzkZFcN2$F@2~KURHTbga)YzNew(R#>bw;tWx-YR4ux z#`d86xZaP_alIeK8Xa5a7%x4P?h41QcI+C*);qSrv2MpUJI3Bj`90$phBU+a94ki) zQ@RR^K{v;$9XrCYqa8chF|H(}y3KKHfn&=ZyTGw)9P4oG7RNdr+vwQcj{U~5XC32< zuByiXi)*k+vr%g zW88>W`Sm!q#WCKsQ$4mj#-2g3VHPWm_H*n&$Hq7|-mz00JI%2M$GCBq%5tS+>^~Ii zaBQ7pw>$O&#~yI(A;*5<*wc>v!?Bkg+jU^9+gmJF8tw1c+Z>zX*fhu9?br;*W;-_D zu}d7g%(1nOecZ9@9J|4>+a3FXV~;rYQ^&SB_9w^62F1E%Emj)sN-6OL_ltkzrM8tYbPvC?R=W5+u79>>mfY@uU~j;(QQtz*|Yc7tQzbLhrFCBZ) zu|CJj%VIq$EQayTv1-R^9jkNfM8{5c?7fb?&#}dhEp_a}j_?9M%(0(4_N-&iJN7rn{^{5dO#9dx%c7wcD~&BuY`tR}99uPvn{ZR+i!4?u3wIqZSQ{|LN~7(FscwI^n0#A|*I}>- zNKspacTCz&Dql0Tt}U}>>bSNkC2OWmXqz&4&D2Tf+=an3@2mG3U_2m*9J4S}!XzUi z?F;ywiCN*qoTrb>Lz)Bedu&(ylf#}qHY}RI65H}zfSp!XEd$&1qep$Tn3W8B;C7Sl ztK{*Tsu2keevG0OXHvkHr~Ds7La-vD_`LkmrKu36{?dGmCx$rP`Ja02l7 zpk3?mqn!G5P}eM>t=}2pY7pUx2=_$zE`-$x>k+aZPD02c$Kt2oNiwG2NitT->sv`J zj9OfDM~-*Efmsie5$=u<^&yTv72yFmN1o<`5FU&0 zU`rWl!`S|tJ|gwUo&-N+msP&rq;Agsai9&ws1c`148nM zy)3t%e->$n%kYa2>PmOQB!YJ`sDpS4(-^wx^e zHI;6Y(>?6iPaLa-qbXgT#ge@TVl6=|9~+|Kq~3Ab4d<-1O8m~iFHHXq%o6WCK)UHU z>GBz_`PvIeyBVeDde{4bGcWGbMUN-mWy|@=EFyQy7W&9=kn_id#^a8UV(O91AL3O< zY?~Io?eZ2Q8X@6Hp1qKZC9avgjZ|UzV^^dY30<<9kBUcP6^G@qk?^Z8y@k)-nGY7@ z73A5vIFsVLT-*WYUNVHIDdM=j&SaB(90L zwN*ok!mX_mZE&AmDCDBK4f=G94Uw-g;hT?2Ch*{Ahvmill^0{r^^@_s-g|jpRR+M^ zCd!JA53OQ3yKEOY@)4DN(!h%#%)h+J!z%E#MOLa2t%mn<#7wu}U2#rbsG=(vUuP^7 z$@Cxntq#9%`ZW?QlipB+a6g0xA>_0RBS>?NowJ4Wd>q1q5gv>15QH2Z4n;`+9fOdr zKwg7n2QbFUe9OR6KIf9uGCt9gSZT!Pe@b_!V^2HwTgNzRE8SllWBXT(FHkX78jW`B zFvrevj4$LU-Q|vb$g!_D_BF@&oI%Ur(^1XK3jc5X=HV9~>?>)N*vZ*Du%9F?{fm|g z(_ia2x(*WM?s~>DSqA&pSKjsP|MU>b>$m^)A(TG)O5^7<7$;e0zeC9J^ErfUUA+i7 zem;+ID#AY?d^f^v2wA`2Ev;)P;yQjZrsF4L+L9Ez6X%LOVzDwlD>dw&j$w>8tkPm- z(Qb}$y%ptmlw-3Uo9|dPJYDHVTCDK+*@SXAMpom;BX|5f9axzDWj38i{>k`xIk@NU zQbnE|KhMMOHSAIq4xOjHrlFI)EIR?d_Yv`<|3UcU}JreQ$ht5$L zb%K$FLnmKY3U4LI&^hoRj+?J;M9pontor!SN|&=Yenh3s3M^ZeKcZ4aYMvTV^RFN2 zgLU|o;WrOI9%UE{=_Y7bGNxjFDq||{jmenGbGCZiENC8$koXY@_dtmId=X}`&F3J* zEre$J_TC6Nw$jyfY-LQxR>rXZoTZk@UL=Zr*Rk(gtd#Fo2$!7n96QsoOB}n*FRe6CAHcM*nJO)J7QE_SoG~RV6&J@nYn_fHy z=H+4u#Tj}e^Y=Z~^UtKLc*;5`FBh-xiZd5jt_{m?JU+?Av4_Xtyj;9pQ=H-ZW7K)g zm#VJUT;ZB=oM#qixL^=(i}4sDYmkLYBeC7+nrKY_XZNJl`F!a6#hESO0akL9X49(+{6`C2wr~UB{uFB^_A1Kc7t~N{MfsIJ&goXm#lhh#z_RdH5X6KrDHb{xt8kZOe4%n2F;jR40e;$}~2?7>n0V8#8gj z_=%FlwbMq(+G!(}a*1U<3ay>?nAW^eASkeQ+62^EG1~i)=J)JSC-<{<+9`3{Fpf%> zzjoS#pnJ+_*_BL=3a_1p4;rGCY{59#(aBm}1=dcx9W)2A731iSj$P#YLG!%PvAZn9 zkDVgt0H0@z$I&0%vncZ^(A>>AJ&r2;gkR8*1>ZM{da9%7#VI_)01pH9w|3e$*k9fz@I!)&E8XkLo_g6+|26P>D9aXIXy>S} z3;xLXw`Q*S!A0*}-+IX3|Lf#WV{*s)ZiUv9yFl;k;sk z{Cjl&9`k=`MZour=Bk3LtB*pkXj%10oO3fX-Q5g0fnck%(bW@>O5!;n=07GT3)a=e z%gp)udxzKga&fPB2}57F&sWHc-Z)l?>~G*=dvBb|$+~^$%3r{bcSE?|-c#u7yAkI- zj57Jml(GJIe``kS&h_?Sgtp)4W;PQM-?`r2nrVGI*V{|hX57&Vfpu`0(fAF=TwmW8 z9WFC4&d`R-8Y`q2&hJC{1{Pwcwe__04sLm7d&}J=GuqB8S<^VOq^Y^-Nhe%VW$IA<>(i;iGHc4@TsBO6h~g6y*Uc{;fSvCR@2jMx(rD@SaL z#3~TmDzV{+ZI{>x#9owG6=EBs?5Ni5|9tsnGOLb(3M^PgU}OwL2GqpBddpI~=A?CN zKV~9rjMkjgx%MN?5D;9q7|Db+C*894V+1Ahnv-r?d*WoIZ?^PFSbT2nDU*%!+N)4h zcGRbuCAe;x1UJu;;MVC9e0#D4->;LPbtCv-CA|gNeXc+mFy{1e*_wM$KsBDFjQwHR z33b_;d#NSKYwn|D5^Jr{{Ifuot!a$}{63}1*4#>_pq#F0)HXY6ZMA0Dtl6m_1g#K~ zPi>d8>mr_wYTXDD7;qDQKWo`k0C{@kF3$ibLiaIRFZhLw`c0zQ3CieipPOWekk~U>)?q85yz8!9~{9*Xb zbN6R!pvX&iW@|o08qS!!E&Zk6c`rr24xLm zS$k+%ltC+N)Y_}4R{!E`F>z>hzailIswJvjU zz+?G#it|&716zwYENBOEXyv~2DXqM1FD7NG7iMdImmT%}W-a>Hu#2h=IxXvQmW8uz zzh};aRob6ZzKv3_$iPDSm*J<#y_HqNicGkSlGQ)6qr?S}{2ZEw7A|!h*nO0&O_{A( zOJ@NI+;f6HX~@?649>6cOFe3ldkaX?N|J01yz-@|vo()XnCZ$3`c9B%1LzlSrUzzg z#4q3oR$AhZ$aWWSZDerGZS=jLTXBKBQZZ=FYw42(q!E`z_AOvmVKy;`Pq}5>Sl#b~ zGDfY{inrE_)*~8<6J=|xLQ@{EJ}zGSDk|+$^l#d!PVKZEvPK#ezm;Z0+r(Cr6&t|f%*I+S4^fOnXDv<3~ ztKwx+GxXz|sTF*yS&+wotYw{GB+S;d&eB}EPA!&AU3Ck)L-cLWqDyR>b`xUgXy$Cr zRur{NyQyM9wh_L$4Z19OGFzF=R%F^vTA!`?5zc#oKY{e_Y|YJeEUI#kY{kHqdy(g* zn^~32hh;vql~{ao9pssu$U`@3nYOMXTM=Pl%9d%J$h2*1%d}f6AmVndCt0XATZxq@ zH$dCz!VubuZcua1=0I>tovoOfBkn2SKN%d;(pH`YcwpNqsJiX`Y~`@FRqN!ulOkj* z4?$rS6mL^Ct;;Hhg6qZ0#JZbBjkS>kVqMl6?ze4 zRUvIP`u%mn8A6+REB9zS3AIFnzw}ecvKi&jR5<;eRLD9l0@{qy%#|lswA@=QX`O3C z(XDN(Iw9gl6LA?Ot{f$GdFw3l+eCJ^uBYPn!el>}L4NVAlm)^+nXQ4Q@QRuT&D3>k zR>5E?73v^=ome{*T%<5t4{1Azj&PMIsI!h5opsQ!uFlrzY@&=t+jH!GwqPS$@GPigX5#X*>ELM7L)v56@OMRAej9sLocNQrC9EIIj16 zLS4(I%$k$h;Ww)WzKr@@bxqrh_Lh4$u9;rfHe&-E1M{|)`zE8?Yq@hWTqUXPg>b3m zQd2GGAgVPtxb-jDE4Y2KRooA>&gxRtcGa6vSFq%-C+bN5M%0zm6D#bs))iLX&9=T( zs%voT58F<<26ga)R9)q&+Ypzk%T~^y|7^-uPJ6=h3nhJ~l` z&EJrgzg1^1za8ge|AHQ+W!n0eTQ|t13d+i6&+Uf^jCFNU+?}aPfPyBv%jg>_2MdA@#K6~WDSlU`r zD^J<7eA9)4kL3E#8B-5kV}j!WYz_Pk?U zfnKq*5mUM@$GB*PVvUF?-73d^<=FSpSd^{?Z~G|SCp~sSd7SzfVw(C6Ty$ydhq(Bz zgGR%nClJ%i{$~(7R4@pd_hB=i#q$QhaHR3r6+}nkwjODDgYOG(&HoUCdH7lt!`Hg3 z^4_wvFP4i!+rXPsIBpm=r)W_0RN1uX<3qoSm&SGV*;+~K8g@z1hCx>ieVZ(6$OTK+ zLsqna@=YbX4Ejmgy9&OKx;x6CKD;@p$JSwAMj6R>7E4eLml%$s4#*+1)#zKpR)Qw} zaP(^EhPMSU2JRK@2bpkxGa5xGx?@-tZ+~8#`Raf{<-0}S9$FT?JoI~(FB7ekd{`SR(C`dV{I5&$>;d~LANu6!B#%BZ?2u^DkkZn7GB1|>I&<)_SNsfXTQ!4RVVAL+Y(T@A* zN8&m*$gT?^i6nhkBkX+y`ikgQWml-5)HoL?qVM=8O(vIQFL3p$q3#rS%E{31KTd;LVtwxU- z;k)4>cx@sjc%AFLT}akK?_;A`Sc`4%3^z}oQu%pgyjb-9WWL_I>?=tYie8@qNu{?4 zPPt?KhCu$LRF-R zcko7-U}e#e=$l2A(NBt|$U5-Xx=9DR7`zM!#mJ_r231c>vg*sF2dnmsywu^#!dP8% z=p~RpC!;RjNhv=e8FvdRXmx|G2}`zL6c$;0>#jO|NvN+HPy{bJ9-4g%zizBnx=%?- zbPj%>E%}pM{u?YkS}|x_v}z#5q|0chq5MBzKwn;;hx+bm9V#y>L;RCPJw<$3UR`Q+ z1J{^WLvVOO^BY(m{h;W%qH?^krjlPTesF-$(b>7i7}nJra9MPJ(btM!!cd@H_p*K@ z;3Z@zL0QoW#VMyylhSDK5hLy8Ue4uwxHKU}VbNa}f6HPCk13VwaQ=Rw|L{Pra5^Ds zj^2*7SC?jLif({IJy$$j@~wlh)OgFhj@RXg8mqud!cf$7drsQ>??jG!#hI@I|2WT8 z(ItbAAJUxpQ|VFOo|l2=`^6cS51jyiO7qmEz^Tihh39vLCuNR#J{(ONJaWj5nWsxn zcAk^Llb?QJTjQbo=liI3JT&NEg=jZdoY(q81bcGmI%G^dVP%7^tIHnmtJ1mr3XS^w zp!uT1)S6=d(W21kY2y(2PC;jFZT%GEi`r=5ySp@HFaCtmz1W}x*xVk|X{+CuSUCgqg z2~h^CDXXLNC42dZ*(Cg!aQIHqB~hutfXe^aJCCB6S&6gkZ6ivH2T-Y0+#?gFK8Ys8+4&)avCb#+EL)dy*=W- zm{SJ6ny0q@k;pjAWvqaVzhhxh-_SdAWYkfC)*m69_YcZl-7rDifqHMj4=bu-x$wzF zONtKl9{v}StHkT@5owxVDSmJCM{zC6+$uCjx;)c!y3lyMVbcp8zA1A7$_aH;7pJBE zA-?lXsoTUYj~O~OdT{W*L%x`Kvh;MX+dAmKR%~+m&?@MkxG4H1U4fkL!X@7L0pj3@ z%P)n+>WI(2Ym3nQNQ&(UT61%@&nJBa0@AL0MHtia~dk%2|i=@8K6kCzt#NyLlX9 zZ8aGOk}iBZBnl0jGd~&UHMAKuR4;;kX6QL7i(w+BZcSMiOJyH9Xjn9A5ap*8xwt8o z_ANO8Bkh%NvQBx`r(zqNWl%`;)VAq z%~t6ubcJ(TX|y!Dv%M?1S0p4+;&Vh>%Jng+y)%NGt8D;f&L1;lG;2_K zw3pbFnsEtI?0H_q{`)li=10>rcfc=3!Y^o3dgh)|;z+mgiBigeZqvy*jVoycsM2Ka z`3|Y|U4#vb<_d#&w^Ytqz14Dlfw(J8@wCt%J?OqDo0)=YUQ~2frWKc_e=pIBVB6H{ zec456&T0SY#&)>VZ3o>?S$s5f*rT~#s5>0cVpSr-?SpoUK2h@hlE-n~sWZMsVzu{X zW?%v7xHf+vSX;^0qjf%%$W@s?luq@w zKOHkwHy!Q~8Pd(z3!0@5`fT5XLnHP#~@_9(R(CG{}>BBB|vsdJJN<8o2Wc;gA z?g^=xk#5OCsjd?1_7;uCmC>0+OT_Bb7Lr|6<+qtAZ6MB$>pxxaRZRPQ!Ni|4S< zxKwpHQswkr+}1`XBpcy1SBvRS8M<4J>9yOXNRLW!4+V{IC8nr!6PogDX-tR97|Vk8 z2R0aQtdAZeM9IC7uS-D>A!BmS;zq#+;@$!=z3-q+;Ck6T!LG<{CyRApeVG)8)h&F~ zS*f!ac0kXIq}5@fjz{cE)=A>(Fi|fxsKrJ}!~*#VTb*Y!@yh(fq|9aFe5GN|q|B2g zaY~q&lsQWhj}8-)G7p!;Y?zpo`A+Fs_6ZY{GGCUQ7l(;SnTJTud0}Ew=F^gMk1#PQ zvs9Wi7B5UJl$3d!ust+POv>z*#8l3t%$p^V_ZH(>1ST5pTv>kki7(PhaHlWsy}Ja{ z-kkM%v7ILz!fT|rmZ@~W7GMCU~7QrCTA@1P{AriM-CHzl@e~mm35^^aV<*S zBG_B3e@dhnhHYW)$(&fk5os0j^3xEzT;wgs-R;&MmF2D5iE>^JWwgC>hn`rW(&*$& zb@3NuhUcub(#Wbxvg*J@R&{nBcOATw9kY5%@mC>vTz|{YUpYFNd@9Ws(Zcnb=v?8` zRJ3b!ddiNYWte2o_>$<}9P#ti-LM17I}x6NJN3&E#xp=) zC~Su?z-)%^$%LjxXsS>H97$;ZWrF|J^44Ih3auOV?`rqGg$J)QV+~pJk7SNYNt|?n zzZH&`K@Po>&aP;iXi=K^D^QLyysnP99TKh1Y|rdtlm58W{@TFz#A4|-uu$$1CvD(B zJLkRrl{5`D(xAop?Hj+HBTAT>Rqhk$6etQM_20S zY0G9WU%6;@c36K-d9koREmfU~1AawPV+TCApaXtGXw(6Z zM74(wNF&o^?-M1@&(KMUQPC>F#*6c5mlT_7&y=Z>e)n@y(inFZHA5M8;7k^!dKfLV zeDLKp<%4%AA6!;mk_{92(NZdr3vlo^42xHBH07Fd@y0ZKC>9?w8tBPoyW%lYvS<~) zWarZg9Nd^@!gvh+DS#W*R8}%Sx1|{_3&;%vLRGjt)o|?N!gD?$sK$f`6tGaGJig-m zVYqEivj;HNC#!q+C{^9M9^D^7JVCB)5W&G`bF&a~>NOHS9>+$yCg|}9Ps90%2#Ftp zUlZmZixHxoG+&HxZ-i?Q?t}1?2&)mY+V(~GC4~DSGy#M ze~0jG2zjfc1|e?*jzY-0-L(jLv3M}TbqLQ!$i?MmBCJDr9>OE+e5##Kv-6V>&O$ox z-je=IgbfIJWl4M~!Z`?ew{{6aUR^Fl_+JR$kMM5@mm|Cq##w=|qC~gJxf&q`faU{W z#|sd?fbc?ugK*`x8sUgR@~MAw6GF7zX5PQUtf-ljEx38}3e+>&Z1W2UZ$S8ajOe!@ z+#fyQml2Le_!WfbAv_l0M%d*D{Cc22pD`h5z8xXNXl4(I7ShZ`&QX=kT;d#`UpGIB z5YE!f{u!fF^D_wH^Ucp8goib=x7`ilpAoVy|ABA>LhM<`@2s0SkJt<0t_WGTdm^kx zxHrOm5$=z0KZIQPd?Z4S(X7)62wA5`B77UdV-X&N@ZAVmmopH;kDAXyh^NiX=OC;@ zI0xYvgbNUkMYsgv;RrcbnSk(8gs?$#E5aiYu0c2nA!i>)A^Z%&cOc}PVlu)T5l%t) zMTAokejVX)2ssxz9^t(RPek|t!jlm`iSQJJPa~X;5R+*uCIVQNfX( z*b0QK+YchdU-RYo$2$HHLe}v|5VDThv9WGHgOGL0j*oS_4k0@B<}V>+-F^+>TM=?x zWZm9@knQ$fgsj^K5LP4nF~WTjK7nw5gdAg7x6dGCoo+|?c7*>#co4!2ggO`@cFL7H z9fFW`It(FnYTgAQ>vRu<;}LSqWu3kqA>O-a9*vN7c?3e%#<`6~Yq`u13hZ;<(Ma8UiEn{9OonzQWEqhVz`uzcYQEoqx~H??gBQ z_$<^%5q_{$v>6!v;nxV?g%GN9!CDMpsC9|yg0sX*<&##%%D7#Xq?U5yDWhBO*xioZ z@7NZ{o^kBYj=ks@mNhbdyf>lcvZvH?xrmTrlN~$Ov3ZUybc{EqH81;i&3lz&^h?EV za_knz?su%)G4@i*Z;N9uI@ae{1x&1T!!3sGFC1eZujSS|Hr=s#jxBVo$+2d~u6FDi z$9T1@Q`vp_9Ovpz>8%tPGn8$Jj{6Y8>M#3tBEesMfq(DM7I_ z9b4#FqhoE3@!5~&{gPw6Z=%=(j&UnA#eVPD9~}F;V=pMw1+y>{z{H z(;b`T*gVHt9Q&|ipLgs=$L@6OUdNtv>=%yx(=p5sO}9NPRu=8$*ujo*yEC=HNshhS zvDuEzckDxseZ;YA9lPGKI~=>qv7bBkE61L9jB^B)WsiZeo%ga>X>_n-qa8cSu_=xf z+MZ~U(=Bnjk2&^9$G+s)R~`E=$G+#-qmDi9*mI7>n-Y~qyI?k>{<6Ep@SMT1105UV z*m%dLI(D36iyd3)SiAvIS#-H$pLV)y9lPDJA2{}aV-Gp@d&mCZ*f7k(RF7RORvPW? z*nW;3?buYu<~nw+V;4I10mnY;*maI|IkwTUCmrLXFZGw-JN5_1UUCd~#f@$kizglVi<}71~Z{ozvaqbQ>Jwy)V`6ZpZF->@mll zaBQn%y^dkHwR*$jEaSJgWBWOFh+|_MJJqq%9h>9W0>>_P>{7=*>ewe7`-WrRcI+O< ze(2aw9Q&DL&pP(JV;KxE>XW>0qqaK0u~Cj4=Ga8XIK$SwoMUU=iyXVev9*qU+%e9Q zHSf0^yUVfr9DCfcryTp6W69P*@#a8f(Y}~CsVt){Ru&!R*lCWP;n@2fTjkgq$JRRb zS;ww(>{iEk+d<3S=%x`j+Ix&dQ?~p^LEE-9Gl?SB*&&Z_8!Mp zI=0%eD;&Ghv6~#b#j$%Gd%&@$9s8|gyi8WxDaxFJ>u9;9edib-#Yde$NuivKDb4oHrU@{rO_0} zra9K&*j&f1bgbR64#(Cxw%)M~jy>cUx8Q*hIQEibc%i`RW0=M8-n(OaJGP%=hd4II zv7;TE>excZ8XaqLtl6=v9J|`Fb&lQS*apXLbL?)%?sx1t$F@24568I3IBTmk%Hp<| z*4wTYD~-lGc7$WcId-CB?{(~bj$P{5<&J&Su}?U*-mwjiJ?7XGj=ktupJNpxVws0q z42wrQR_E9x$0j>A$FT*DUEtWoj(x}R$G+&;M#t`U>@mllaO@e!wmOCnUd;9- z7Q-0t*a*kQJ9dO)$2oSQW2ZazUdI+Vw%D-?9J|=Ds~x+>v6~#b#jy>J-R9W+j&(cs zC&&Kk*sgoV`o6_t*igfy4oqAk6@u`j76=zKEiZk~A zuHcC=EOXznxoUMsLE7u)43r!o=jVRpu<5<4%jL%gUtDaA4NM z7=)N1$m2&kIy$@N0}vjD@F0Za5gu&mb(W6CA?d6`rn4b{k2M6wv>`CIbE`}kA&PRF z#3A66RvKq$(Xt(WB)!|Wzsuvff8{RP>J6e_#KPi zaQt|*Az?>bW&V^I@qQYQ7x23|lkZ*c2hK9^Tz=dvWI$=z;331Z*02j zoTp-I%YAiEIh^3bBn}HZx7r+e8m+Mle#M#p>8&;|W6^SO`%4}lm;d}Kg0;-!3x*_H zZGO{`WUI~l3`w@y{G}nB1@yDk<^=luR(K8lN4DC;*IXe&7JuhIJFszWu%8|0Ub@{a zldq4y(w(&Gp&89WnshGqsQ{SFQKf^n9MH0fM;bR6V5bK#iQq^z?o7irSDILA!N zs$J9-N~x+_37 zHceDFCMKI#H@9v<-Tb~uPp z9c^%s4l=!-9U8w5Ht&xzmE`t@?ndsDd2`mn}d4+~u>ER4-W6IDbWT z&FTr`N6mco+o;VwfBF2m%U3pBh^>$pEj_pYo!S1K_VW9`vbo;BR&}pbW3Sx_u;2CE zWfwK9fEVcPcy^`S5sj}$qF2PN(cN}CedT{&b6nZ`j=N*pnP+YN($;w&1pbEiSB;D2 ztT=z(qE$-{SvGG@^un8W!NSfyeY~0r7G}bDHD>%_$#7Ne<>3kgm`U)YZU$4H~RlDhIL^!JLLj0)j=iW++rXy@pS%Jz=k2Tf`m2w(BYC&|@Xi~4Jo@7|4)yU)&|ET7>AXJD8=yeTJ*!;Azl#{Hxi8eEIwZxqFXK zel_`acqRJQsJ!y;)|tRfmMm+WzhwT>m9tkaI)AB5bzj5g<7ncaxBn)<(V zc=Z#}H+4$;=3Fbio(;15xqk5-ytxJQAd9CUB?^}&4{ zTjkiw|E(KWmL|~Hjd!uhQr>|wIi`jK$6Jb3y zQbd>(ooO+BF_T!S_zh#~H;T<@>wS6Eh#P=LFRvQ@@~Vn9gyk=<8vOF+mb-`RM$u|@ z+OI!b$MfEH*qS%ZV_TmLV@xVwYtnFT#?MIgxGdEX`p5>UkFKl+J8no5Z-PSZdgv2h zwhb=IxIaSB@qLGwlu3FhDGikD$&=8z9ALngGN@2OrwiO+lI`z~vY`0IuN_x3-@Kp{ zRAMf!mR{3~851k%>pcF6Do=c-PC@x!jsNr++H@p-Jl+mp;Q2uaY3EvmRQ+iD)HfJY z-(ajX`lzLrMW3)(Y4lykzVFzt9Q%!9Tx3o8@v(#QyTGxF9ph3!O2?&ulrG=@CYQVh z2izAz@aWG0IVGHu=E5DE_*cVu^Dmln z(aQNNUiF|6+Mea*+J0}?n#IEI&6K0sY(EuowLN2Md&Wwm_4u#Y28+ozd5fzt7HkC) zwcI`UoV)m>@&x>bM}@4#Yj_?^ZYd=1zMIo4txwnjF@``ubQYK^qkx#;7Qp&{v? zmWpKTsCuQz%Yn>| zgSE*c*IT(2$Fv*^GEXsnkUqN4Ex1E(U48!Yz*ToVi%F&&T$En7&7%wJkxXHd+0K%1 zwnJwLN$HCT%Vf3_kCt&Op#>7Uq&3BsiRpN2?$x&-?m3~e9lmF}MCLw}Xn*`fY$me^ zChJS7EP!WxDRp8c2Mrz>$g6XoDA&VSA7l~N3CT}`NAdhU2w6`v%)_Q3t{%pidKhD+ zGTJEiIh-qYhsDaGyBybl-Jsvty4rCZ1h=1Ng(Q ztKiz=*PNNZ2G@QYv*VyWdE~k_7hBBjh?$3GI{?2+Sx<7jl500Cn){#N-Ea8E8E;xM zz*7DAP+KnN@Vcfnp=z8at%7Gf;#QH{Bv_BRP2w1962~HB{lXDtfI1FwZ4!)WlVD5- zD8)EHDR!sD%A$K6d)_f#TPxje@Gi}}hsDsjIL5mYO1HoO46s%(FajqD;jyH6=#%BP>yiyeFl3 zd23eb4s&dxW9uE;;27sgnwN`GYhLl`kvD)pCTO@it`e8#6-a81_KIGOdvtPCTbS$B zccH}G-j{jk)wJrx?7rmKfmiV#$C(;)l;Wp{KE-+S-VEbwRq+UpQvPmHB))all6@;1f?F zcFE(zn<L;`RRMJFmDqUoXt= za^xA2#|JY%(6Be6eNMP@!>RdvFe?NNUwMk{yk{PtDxqPoM?R08Ijk+8&t5{qSDj)z zR|y}$XlZ&3kE&UrI1W$%y=aV_UW)F|u9pRjUN2w!QFyc`h|h0= z*TV1+0JTH=1(_`KyDXQ`$Uc${{XC%XtKI$xf{TxSNc#P>hx6`!@-!fgvzPvo?b5Qp zWcdc@6-5`SSC(HN0`9P=9cdz^yn;HhynL|HuzdE?dFL;YyY3BhRxQAXP4bp?!}3*2 zS1wvIzhU9*75X(4zLn^w*7|)#p}!0T-ihmvbce6O<-QVe=vaJbRGl2J`2O|bqwDmG zA-;b-K;FM@`gD<8$kBHTy?@P)HFXqt|N0vAm}O`OH*$Q%!C_=_Kkr{3!|^pZgf8d( z>whfDM0bGh_7&Q=K7^jD(EFvmXGYOq#ur6Te@t84m%*3s)50RJ=e^9YBm0~7{Ske1 z_JWo3moHt?Fnj)r(PJjeUAg>Ue>?L9$hKp{^ICG8RL4B8MWWMA#l}>xUZPW>!NH*aT|A&gJJfgTX|Iud^lRfj=C!_o zIvg*YQg+l!13$rnFW`%!F9>2mQh%=EJ@Z-|)jNgji zpYYpMjDK&~yN$soKyMh&)VF1?=Y7ePgU|E^J(CT3X5p?yUTb|lWxdk7nf+Mh&3g0q z-|o#^zMDF7{+wmi!E32}6IEYL1x|w0d#V%uwf9u3M~*>>V0!rBW2z4p*01}W*8;o% zjWzb;|7X~v#Bo~Ugu1vyG+~ZqoI&t=yN&1{yAkKrOIftpVx{uQKIheC(M$Nx7?xK@ zzk==vSe?a6qxT_JE!Z53l}7D|?JL+-7AuYT-RXXUZL}D+JwS}Nn#v;HhheNV+7o@$ zNWu2DSpV<)UIMx|`+Z;BDZQ+h_bYEeVbR!o)=cYbn^t~W+c{OIx2+nyrgh#+FTdP2 zZNwSV*S0Q1bj@`O|M~LE)3=g1TOrWe)<&#cgY-_MPtR7$sSqf%khGe^Xx6s&k~E+} z?s76oL-qMkZ9dfPyjt#_>?L$Ks?g$0%$#K}E{e}s?Be41j3q8EiO*Qr;sNm)%UL{7 z&lV3_+nSUhQv?P5~@F1yF(%Kp|29r3e5Kg+#FEOk|FQXFM^1h@MXn z@Ug^DONA09!hUV56tB>ogN9Tgo#6TDJh-SYDB& z{MDB&q&q5G$}@t-!hGYh-6=(E$>WAu7`6^mtCOnisB9_E2x|K&+dcf1E8B&E{SvRX z`gT4hoRnu}*S}KP;vD8nfkF!lC@rKy${%5j3Q7>m+4& z7jA@w^cK?4=HBgEWrv38EX+49SR|<}Tq%Xh7SbJ+E#(-Q9T-j$hUL`B zgkU^HHW_3SgseUwV?0GR9b|PvR_kO!u(mY;M7&vRT5DCjZdSCF%Xo_6GBB(WhG8$o zcu1xrQdoxfzf?Hp-bk6!RFWKyXi||zSnfJlvj_>TDWw}sy_OJWtW_u!zmqbhGa8lT zH(OYvP81N)j8Isl3Ht&~t%RNcvW)EkB&^rARt0Kyt7ww~NMu^u8nU;H340N(Tr~|# zu)JXjjY<`kAgtH6b_Jpd>#*lB0oJxQ1yoYh+EyVpV+h|+S`lrg78>R?!mfOFLTv1; z1R+kB5b`q3L#hI5T8UL|TM^~( z&6XqG#WX4Vu0YyJxrP+cx|L88O%C%9Dcc}pCuJKXtkcpOuaL@kNlH3n2pM}J7Ag^~ zKwe>;9^@KTtx$n-g+c|Y6q15Wj`n;LnH+tA)w+}_fkIzPP;>UQH(TCNv?gU2iYCdg z*jP+~o4fexmrq?lUms#XY9sfmQx zs0w5hzUg_iWo!ycH1=XV;U!iRigb4^6ltg<*Wy0BOG>(4La0eIb_Q}tJiO4eqQXmt zutGz2;wyGj#|oXPCJIY1s5dCIQK>>+-T9(Pa+8E0r?leJpNT6nQdhLONQx+ebvS?KP zOa_VFDM89h{hn=TQHlYoJ_e=_p6Q(mv3aPbCtisU|6VA>In<@mN5L3Vk3HtpK60u)J16PoTQ73!TBJ#7ixs zY2KTku`_^#Z#Zg*XkDslJykJwrdC*jd(~MyWmQmV)@tUb73fT+a^c^MP8xDIS znh|ycI!I~h8Hun?&pI2m&@iJ>b?5UEVw2X`3$a0#G2tbmneriF0ZlD$ZD3o8r=>MW zY+!{pscplI?fFnuu5Cp$V<)N@yDrUJAIKr`^iXJ!fwWd)0*Ppr zw>%(}c-YIB`=lY^lQxlwCM?tL7ebAyQwT{s&uqcj{7h znpY@?FiCrY@k*#dUz0>*XL&=YL*)?1G%9n_kV;smM>unEQOz>;DX&n0TGd=i5vtJF zL>$X&a+C*kY|@5My|N3TMujBBcv;2}GWJ4jRFWL_IwD$mKD%0l#0HkPQ#B1CvquP- zJtQTaF@%i05F1rq#?aS7Lers(;-u9IOK4ODsu&oRK_Rau)k#J&n?Y9b*vs=SP0 zg@%Ndw}V{MC5R0SlH|12%tYmZxtsFM-L8@q2K5A*&&=f|qIIbbVO}XMeJy2qg*dH%q!?6{FNX+_?&^$c5{WHip9&$w z0*PowD2ZvpE?3L$GR)MHMQb57+^pQ0OD~0o-M-NaqDQ0)uWS*C1H5VnC4NLl%0&HZ}~{IguR`0 z&FQ{K>LWcav9@#A_vW&fKA>C)+XFc)uk=z@%Z*CK_8(WgNS?m+)T1TL%%^G!*h^7q zHHB|z3=vKEr2A$g?8;{s7HTC3u_<5~LpextyYKHBgt!B zS-SRW^KEPF!%FE^UXxr7A2Sjv5ltx4B^bMzL0&OLS^+U?S^=Xot3&gV5rh3I37un#M=$5GcbR7+&Ck;+69 zKIyh6Owy1rNt;_Nm~KDDtILH5E40Z`7cGQ(n4E4bR%mDQ^GV_(2t;%OJk%NSZM zG*OqzAzaNwQd-)vj9o}2@pM;bP*)&Yld=z?Nm`)^B%*aIp(L6d<{whFLB_5pC_(t7 zr8Qn5mGP1k<7F8`s7ZwoVxbbz3gi{m>6=Q8s#d5#xk8}=RSHQ#CP#a|iA;{Zd^Hm& z^tA-_X;~;omzEGhO$vpgN%AW;mMT@CClJjPNFWi-?2({0;|p)CnERw5D?yBBCNe_` zOM`@OIEnQBHLOt6Dak0J%~Ty~85lc*q#%Pj@~zgHZ?$^mB?Vc=-h8Sih58s6RaY+b z?_Qy%X-}YoX(}nER=cVdLRD%aAx@hpq!Pa2m8=iZO+ksqUW_Na#A-s3?yiL*4Rz#N z+=q8bN!LpVHEG7qKn{tA7id;gc<~cfXvj`{B|X_U_X|rfs5dCIQ4JaL>dqHUlGE%h zqYx)nlhV>{uU1Qtlyp@|ia|zIPhx}0^Xu5CBqdFi$YHk_8a215ETp(1v?LR<-OXTl zy=Ljj#f5iR??x|TgoC`{X00mM#qeG=Y?t%j`MQVsRA^kk`!dPx=iPi_QfUaaT48-| zP=79!*x0X@ngS}z7?#ioUcsFR`bcnEAExHN?!o&S8uPZ9 z3}RRHexyARn^NRl9dy`YmC?zdm!Ph;Mc(M?O zax=a#yhXB3DJKbK5B|q?V?0Hp#nyg2qB^wVaU#)gwQS<3wmTI zTDul1`O{XDvJL9X*WBtU;U%J(Ekkx)nm1%uuNE&4>>+&89w|)HwiPC!gPR4@YWC(z zE24EO8W!59a)i=Ka=KO3D^;j~i55auXb4$}wSk&eVgiY1mbW}0lz7<7nAT}X_@qr_ zq6tf@J);VtM%5{VBp&h#MeC;VjGa|N2-PdQ5bDaU1i$E!veUezY=eYJ+7padLKXU& zB&PF*P>0GPj%ifpq#>2CE_k0wRI`kI$}3c$RyCJWgevqkQN{9_9OXeBo2DUDuk1po zQ6Wh&UY0S0jJ*&Wl_ZCaMMNvlXIHC`*ue63s-_`i4L*d-9+HyI7(&Kgh>a>QW9Vxk zq3O^?anfpqB{Zr6RSb;EppaLS>Le_Usy)9#C*|5lMC-{X>`zqL}JU>r$Pv^Kq8tEN@AL@%hj^G3^TQ4 z(OO6iH!FAM(o5lCw{P^qICKROgc1lrYR+w0npE~$SI6)k#k+HhHmy1w_pw%#Fhxb; z&=*9IUgas$8)3O>-W9N`SEw(5M7s1-5)mwYzh7i3SXqs(o!=N22}KAItzAVE2~9N9 zG$Hg`%ObQC23YD_01j&?cRXv(Fq!P)~zGj711)g9T z`|{-osq!+0RtrtkrE&;YlUDeo9n08-R1#17nn7KGXidsKgeK)0QbeGG3CBu9Ofm_ChRFB3gmG!a6<3HL6;n0_6&Y3REd11(_V}`6e#M2sJ4biYCdg*jTDmfu2A#Qy_svG_yy7+8`cI$h@HmvDw2) z5aStSh775MZ+c!}3WODEP?AwZo2fd~GO!X1l7bBC$hTT&zSZiLmlR|fd-JK96zXGO zR9(5yzk7w6ragfUrm3WuTJ5S<2vw-L+7p zp^jXO`|vI)>3RvFCe7Fx$RY8auY0&Rm*>}UtwNGwwl%75H>BNSXjD>ZgjTCNSNEVz z%x=~YLZ9qXpX_y0`UQN>#g|n>Vq3pW)9!h_A@l^0Weln6wVwI{Dyhr#BDpby_l91<$9%jQ7HQYO2$)^8(19b;$_xDdo*f8>DLK39(UG#)OwNh(66563)~TLdf#gGR4?QJY9PR^#; zb{F2=7SW8IsA7e7efPqr9o0!+P20kq>^}O?oc%0YV52MLa099kXjhLEW##6~5_VPg@|%JbRPDkL_ryq)=8WDP!~GJ8l$I%5bKdm%Qeyo{l* zg@mR<7sW}d6_(Jb3RE#LDuY5^O{$ZyG^+Oe3Z0Z|9}%r5pRhxr@}SV}d`L=5_wy!N zD2HVXA!9GZY0VSpU#n2lG^|ilQ&OzZPSq)dYSlzSY*cv}!wL-vEpG?8rb`eT7$nJQ ztC@+)19La!o4Z{hNiklQF@Z!hD?#Xuus~iZt>DE^!p@)Cg(hlL6NT&z>IpQTsZ`cl;L3UOKiNinD@UydGSFDYrNNr7$qluC$&N<=eul4yC2u*=o58y_>Z zWYJnk4L2)y=F&^yVYhGe!Z>sV5rm}*0j78LF1BT9QrT;B@gBvybBi{uIvn@=2%>~3 zDiVjjAcFKNPm$gT%T@EPfSrh#zGWxUrLJ=0MF&Jo<0Ues$0d`t(Y5m%D^`!71$oLR*_HU^M@tW2i&_aYzBgO+_yzZfF zpAfc*qN;R?aK$`ANDjlKM!GORR11>I-U$PL*OWeL%Sq zwg-fkSK5Ke(Wq3D7#Jk1)Av?I^6<`}_gGBQi8t(5%RK(Aysd#v?5x)YAWJby>u#}urR1YAt~FS z{;MkFWrhrSb?5V%q(byDMc9WG+T*Be8mc8S6?AanYSIdmbaNCYX>-q1Il6)p`&8Nl z3M;fJAQX!9tffcuhE!H)Xd){#ge+rUz+U2M7s|^RS}inDm&zer%^p%(+OdpXNG0)f zS7%UHAX<~M51~o9h7{4dl~58*4)YHw+aP1t6O-5Z|QPm0+C|4*{ph_Vr$mD3xH<8KFm#=05g}#=cKC2Do=+Y8Gs7awvG)aEN z#!{sU^aP@r0tqCdnLQHJW_$%_j6!VouoA?02ALs4D&ZSWBE5eNE7WvKGKy$3Rfk#z zR)RrNkU<^!R_n~STD|g;f-GZiK2?)KeGH7MD;N5AuTaypC(yw(l@wE}UDXPqDm9T1 zr%e=63E%Xz+A=l;B^rA%p70W@2}QcQ7K${~k!x`u-X$enFCo;V89M_xBpzO%Sy6d+ zg2ge?ga(Dm&r}nIB^cBj6xyg%p=jOtqDgZ4I@B@>abh(oE!`Yz^W_i$(p{ZV)sxt) zR<0R^*dU{llr&W$huwN;)ZC)7$+z=$kHETBYM-#;yR_mHgZl+Mt{KGi>1s%9>$hpz z1J~+Qc0B=P^%qjrs~mj+RkvoG6i8dHR3fz1=FZnWxcP?JDm0(jDl}h*S~M}AUqf~U zcDLGTN}!fzy^_CMuHI6;QO9fCU)4nqUM8DO9w z-@beA``mp}>6!We*So&&UEgA@fjsrw`)oVs-nvzt9x{%efBd?K+)wnBj{oD=J^uK0 zkGAx-;&-90Z~^IMmp*>zqWEOw<^kWR%4G1Tru6vvJ+wDu?94cZ*V~9Y#&9lmg|#(X zs}=eI*V|EAT8DY*diToi6OvSOyHszC)t)sIV`*u64@>@C+`+SQYC@L%LT-PFbSx-@Fu@R}Wdo?VK8yX#bZD$rW&7d=I zNzLihd_<)%?n>jhJ4{lG$MS`Rq@{TV^>@bs)@ru&o8UHUz6i&Oj3X+WR}Ak`Ep*=A zKbDqOwI1SH&6a+T?`zdLZ9pw9H8<9w1*Eq+_iD|YePP{-P-m62GR6>M|Kg+F zGHciB>bg(4tG~Y{kGFmI*TC^8NFi?0GUEHZ>lLfLg?3!8ncmYswRhEt&U>vk;f-p= z@hs>>dM&0_?~Wzwyc)u_nN$ywR+s+4i58ZA->)?dxLIYoaygI;=FU&`a}9 z3rD_M)}q}@E01&K8$c~OjTIMGEMre-vu2X^QIzI&wDs#D{0c@^e0Z77H@wU$3@_{P zCEpeWhpY--X8+eAT0nl*+iiEsp_(jx^5D&&dNWHpsA2^F^S|yfss6ghRr+B*7MStq z_^rn<^Sn$wyF!r}2hZ$ij2$V?CynbAUuiOSlyPvDU-z)E=WE!aQT2&e<*8#=HqUd^ zvn|Xr<0R%N^E^X6TY_iC!Bb1!K}+qhQhP#Q83$+ikGWXb6E$pc;Ov1ldgk9&#nfF{ zr-SmLWZ1<4n71gY1W*GtD^^_Y}ho%uDPHKl(#;R}oKT3X3EjTwAx%uqJ3m_aN5 zTzHM|h?p{mdY&}-ol%B>t*4=1$D|A&u`1$Z~?csb>ESzqldsR)UWj|bU zuULnB#aJ#yuipOE>RB7$V0D?JhVZ1FCRIWmrN$BYiHvRfAY-ha##pTut4??=P2;4y zr*YzV`F+9Iyv9kN32T;A6M0WMoAh$jAnEnvu{5zR)Y3Fg`iP<)spLs3wB?njPc5Fb zIh+JvSPu)8|HHyKHSNwjty=RM)g{fA&erRQUdrjXU8;uCDi%IUt+t_sq^0@JtI_N5 z^P#z2@^H0~LF1&=daUT>vDA`w9wiU2&g!M54X{>2r*CrQ#xq|sDK^k-k|y#xIvPjh zb<`W%ETnkW3YDkYILNAHh*HI*Selyu_;n9%rk#yb>uQ`@TjRF(HhTHE>zO4zeuebE zeM7y|TIj($RZDuBqtt98QfK!XV4=p1Phx&UOK+PUHrpyi=+r8v)=~N8zbJJ!dUctk zmULgDR534gcCP^z*86+K4UOUaLW?8P>oEOB+NItsswXYmAY-ha{z-Xaj^TZwI%_N~ z&3jOzXK1kuYH_L8GN>i>YRjBmDmCu0$5Kn`Rn*~MF_dk!wyduDi7=}|9ptk^2V?Lh zZMLM=U)R|2o!kAjjQGCqx(+kGce>tdZC8o^$A8R)uk7j!#XqaXx%$W3I8r@rEw*8C ztRFhN6tZI$3ss|}6MHa^9w3s+PrcwRC#~3QaEib<8@zVIkh3bA@Dd~86+6~k+3?pSVI8>_7~Ry)AK>M$=2 znNCe}yHszC<@;2$sipZWW4NlVjp5pC;<0&+lb%Qo5}Rjg<^x7O zF+x4qq5053kN% zt(yPmHq<+f8|rPU#glefPf=>I5vj9#H7tx98XbLYXBIWhpfhku&FR#9M5Qq9O5?aY zOj3)-@`Z(@rFjPRcgF$NYPR?ho#R)8Ly99R+lXR#mujK&cJnG?X=zpKA+A-A^s|(& zRp+z;wYb#WSVzsmt0nbn4YRGAmpZGLmgeEq=xg1vTC_E`X)^sY>Rt2`NP7`<>@YLz zpoY-j*pX&vS3@Xc?4oAaQVlW3%4XP94WXW~qs%Z$4Hc@&${)Lf*iIVPCMJ1QuVIrv zDYivx>mqH^yHlrl$r+ECC_lVD5#3y0lkw>AF>{>ne2kk(c@Ukf`-GzGFUbG9+}d5E z!$7&!HPn~q_SNxQB`rtypfPl@tZL^&%MNh|%B`-!rwHOrYch9e&yGt>%yf!nexd$1 zxx*pTZ770xZq4VpCos=36Nl%a=Kl3rtpoL~uCZ^A!_4ER)CZntp4*S>fP)z*cda0`Fub+qjS=ekQQqlOOG8<=l%CXJ5o zt?HA0T6C#IKmGwZ{gS}FS{l82va}(e%%&4bPi(ffcqi%2UU7fT(vF!VU*DF!;=0O` zjhQUBWqHO7%3ozE#!Q~SDvM|6ldM6rrV}B{od{X_M93;ggsg}}$m&Rh%tJ=dE-S4% zEhc+ej6mlTeT}QOdvNW{QqjR zDW|wneCC?ZbGQAc+&%xXZ{LvgTRk1PH$Wva7|rLoCos~Y-ctYKM%y9PK0Ju`q^?0K zg1AGmBU()piR%%9EPDBtJTt6)fsplomrXb zR&_N>Esb?}tYTjV+~ZbT7`ap-Kme!PZu0i67)D6`*@x!7Yp8*fJM)hiI zjm_(9(xmM+k63NJaTs20C9@P$(?#iNt~GY*NwqsK&67sS7uLz(Wv1tLfQ1?)&L>Vy zqk2+zjFN|ol5z~^8cx++Lc8)7&m;oOl?x_M(@^(nRUP zD0z5wcCUtoTAGGV-{i`6K8hZ=UB?ER%}Wz`2H*B-n1|O<50aYG6RD}9q@`)L^k(X7 z)!&nP26cAH!$nC8NMkiy1GP|^HxMNsMj>fwC0nb;wD~A`26c9?0TycL^v}S&fw-YA z#qjM`L`(KV!^f$`q@7udY4cqsX$UW^&BAFSmwFq$DkjylAMRCcl)T!)E0z{B_}VB{ z8k2gsb~@!w5f?UF1GP}v02}IU7G7GKcdABj%hyK9GpKVqqUfce(?>~PsI8^ptD#yo zH(Unl5mlb`>S1k{O|3IXzA#D^^HOK8V}OPAMlYRn{8C4!=4x!d-8La+aH%(xRyMC# zT2EtAHK!lmeW5z14X8yWEv==o4lN+P)wx$&=Ir50wlG%fUTR6biaPvvuFJMsTUJ-s zyR5qoW}v@|-6r1ZAXjG%lP}TOao=6nGUC|B)Ybm+TddRyx|ZadrG0p> zT6Fs5k`|lpOx@CG)xNORGHAgrX?5`&@${!PT6vr+Z+lvF8mm~SrFB};DzoH6PbElRhmOU=WetR1&CZGsFS9Dc%dA3P z>TZ=%hpY@7tc36~OCMflspZ_oac1d7>d1a*f!bVFMRGuSE~(?ltYULnIkGU0uh*n% zSeTV1UKOOi?z!|Me5@?v(Zv@sT31$PU-wAy&9B`|30{5O%^IjiXuHf3msixK9$Yd` zTxL|4*jdKGMayXxt*?7TC?`{bS6}xq4O9)eGEQ7d>QV_V83z|Gm@Im1JlP_xs6F#Y z=U>YLrw_L7RSzkZQ?INFSs1-qEqs);rnr}WnBqc)CE+y0c>9*dGt@#I9PGx$P1&t6Bnji|`LbOP5jj{Yh#x{MBMXWfr7_KcFMB2Q@Nl&E4NoT7; z20Y*z(yQ%lthURf5<8%!m937VV6Vxi?BO(YyoA_<*pnxXk|%8;DPQtN$rqOJ($e&0 zdY36%wQ;R-IwEZ*9i)3{BJas#Mak>v$|jW#vIj{^^GzsJuFxn|8#lqvhvxPS9;=rO z%r;6MD@q8_%Hrp0r`Dk1KtLYqxQ?u`mAKlO8{xt!DA?UDmnQQk3R( zltMVKHcFZ;y)w#;b@)Pc_M{$Oon7)+Q7ZM1rBiD$wKr@+m-P@OpGTDH=B1Xj`6zjK zb#|`-7HZsvxA!(Htr|*mDP|~}S9A8mGq@C!R;*fG?_M1ysk2M17Atzy`g_I8pcIn! zm}8VQ&i~F0^-kl4dZ%jfd30G%QEIUfsk3_xuu$X1kE8Ldb!Ji13_3iQ)SOOD&8bvr z9CwFFYVlaUFiIX?oz+WA8(^*OWc(b%tuBW1J&q$P+lYz`-1=*w^LF!!v8vWUu~17> zkMt?m*Q&pF>J6yHrRK&uYL-DQsaI>}>{8vl)H(H1i%MFWJ637Szb()z;=R&!FS4t@ zzb23GTkfxc?Adg|$)T1Sz-!TbJc6W+d7oSubV z3#g^LSIGvhRTpJxmGS20)uo?sw6J)^cund1l2@x0dQvSjeGKTZ(zHVN@`YWruluLP z$N3KMafWxk7Dnndr3 zWi7tcZ#%L{gylZIIMFP2$)G{C~aTK&S{pNH z9~0hVU6JmdOGQ%d*X<#^P9Zj+rB$u8*n>O9I@~LUb18cDS}ZNc8yMhVb(xp0cdt&9 zD%lT}w6qCtRqV9IHZ+Fo=^u_af;t%(Q7uRsB%N)=VilchX&NVew$nJNq_c?=_p2nm zemqt+)S(khpEJ~)N}jR8LM_dc#t~`p-mp*H*Vb9jbx5ExynXhbB&A6-8)i8all_`6((KxoFkm;e26~DpsxL zPV0zX8aI81D_c)R16o?i)YwC_Nt(zrbTp30>!@dzwAv_XwgC@mQ3p>=g`}l8v@TQC-%D$=wS^<^_|dCk3+rKO)kaB!{O{aQZ?hH}=(Psal5S`r z#SK+|cN}1?hE5+Pn{Bq0khH^+>hL_4n$xMNIh8tXVVziUL)GZvd~K8}wziA4JY7bw zdZU+bX!LTa7!fD32(P8JTk|?8FRg4+4A;|`RL$vUB44P^9!s;uFATUxs>Qu}EqqIs zSS2k@U#1yKjn%rBT0ES46?OPm1!Y^UEvu{RUStP@cfHO0Yv}xct*L`N(AP2f5>Kt; zk12dw&2;Gg-g&iuoEA%6L1+K82_KStH=;$SpJ{8^qI7O`lX^lpEit{bX?5vWCR$i} zxoA!4`;u4NPItP0T50+u&}DUKg}zz7R{L%8*MpRmB3`k%&di)X&1EHtR1FKWvP7yN$=?hSPAki*99?{Sp><_t_I0n! zIy(o!tFOCN1J!~{#)-?a>QWCb87D4Fs!QxFg{Py=VxODZ#6+yF~+4gGhL2F@BQ(t4Y0N)oKxkrT9;x^6>Bpt>}ZtythF_U*FLlXEv;&6qoZ>AmgZ7R zW4LmVbP#C+Jr+JT;9f-?+%bz-TAHtojW{X&bSb(oi~Pp==%?NYrlR(sY=`qt`$ zEMmo}#c*x5wiM=}HKlLf8Yi8t21y^$G)O!}eA>_~-awZ%P-N87%2r2Fuy08Em8-@{ zF9Ro$)PGh;$leMO? zv^3v@LgnTWrE24m@$;d%y)=)diCoek=}GWd(aU40r6|qU7OHPs`rg&BmLsDUucO@# zM;rUX9V<4_VqV&ZFYL0;wU(kZ^%(GiFNF-6E%nlD=>hjP)!CDJcy)HkV@0XdzbD<$ z7E^oKW(PceFsl`U5&h9n9 zLXF$-DCuiEv#4nX9iB^SPN$~kRH`(NyTc^4cr0HSB@eI8>ZKbxz*^nO^kboKXbk64 z98uXuRAk^!W@@4HcJqp{s@6cUP)k#f^eNZZs=s&Y4XDMX=Egc|mO(A4S8L|%Qr*1N zIrUPDN?MvbR%y$>Ezm0BTea(6WLJNGO&;$!?yrI4zPs*ub@pD(AHRN4?4OUhmofWW zV0?qu{qwn(!ruGHi_!AV*Al#%?P$e?6+1LNA!*H|&LH{17`|O%@dd*lzkZQ#qx}65 znOnSwj7Jw=V8~w^QJ3O+vK>xbn$;zqg^UxI8P%oOOg$Uf%fxGhdc~c~IB^-KE-l&N z7;m4)GfrGe>e3_s&RsH2Tn4L4acZ=j>}BxcvrtUdl|_xW5pKNEtJl0@3FWNfc%N}j zKMQC@(Mtr=0K)`v?TzJ{cw`PvTD0iShy zY#w?q@NimFd>&(Ak%1A#@V-#5a*tKE`4r)`G%Y^;a!5m`U)Z@3XlW)1*rFqu9_1Z&mEH#WpmC>**hklTarEZ>_Z;X^?cb6^m7L9xsE|Fb|EBKJMvk z;>3MJ($ieG44T{Lp>fm8K+UP-87njpFM~KDEk6A??Q83-^)geh0Tyc9bVOBaKtra- zuaLAf4_ByuKS;x=IUP}Df+MPi27KFF!>0J*(8OMv$I>jtS<^V_?a9Lxj$E{A@o>H{ zN)@YCbGw(<5xq3-fL|6B4d~QLcEDo~%_eCg&(P60BCn$!MpQMgC~39<4{1?{??yb` zTAF8wrFpn0X|}j_z-!MNsD*0F)@GD^7-~s7FC;Ck+19GRI}Wf`L&rx0?i6vWyr&`q z*Ktdh#lvgMX{=5gx2{(&Ev?H`_4l=HR&C+P8+Y`oH11xtQPLp)J2%wZ)Tw*tz1DzQ zT=J7pNO42ef5K}ubowaSY_rwjr5SX1E~z=4nwnFov;Vl`hN{uS`PwK|Y_0CTdnu<6 zob^U8-_RJ#rD8;!$RfO!)^5$msg+HN;d&aAsyThi^@Zx3HlP-lS}c4~2S-^g>ZPT* zV_W9$YfFvQx|do~uc8kBcA;#mwPkg6T}z4YF|N0ne=Td?%aU&+vasqP&!KfpzC_E2 zw=&m#TFvz0dan((+CNT9yS}XLVzE=Bism+?#qFvI;<6QZaQjC3u!;)|sV*DS!exb9~3(|+-S5qgOqEqX#P0)+T9ouXZ)ZZnIlip+9tA}u0>+0+a zJ-j-n;fp$aC*!+vJZl52Z3*X8Iek8LDfU#cHsivMM#;}wTVr_bLmSZ2sNX-(<-jb~7Q&(N@z zBNM&a?Qp~f>ef?ipvAm2i-+$rFRi60&Fd(Id3d!^YO`=rDmT{Q3)R_^dU$nqNzMP^ zV$rF!ScYD<*-t_GEba4%UOo@Cq|Hak!>hA<4X{w-HoU!i57khbOEE*)8feabcm|hZ z(u(biu6M5vlhoOz*2Zzy`g_I8pcIn!m}8VQTY8_@Z0Q}#7pk+@(b+#KSDCJNuTuYN z{|`3QJJrE^IPX*~E_GQQQEIWI>OA3v8n@w5(${KtX$GBvOWwS8=aQP!K~@^a-C>ei z(uGm-@an8yI<*1T`gjXRHX(*r!c|l!Tf=kAUOOLw5Q<8Dw@}#;Hr$)=kUIs5d3&mtz z*+Gl95x)hckJ4HD;uT9MXBEf$jC1Ox6-6&CtgUga)|7r|@X|{CMk7ge{doKK!ZT=v zE_p0npL*4^K3wwfH6$&~*LI)|_^jJw^U!;Nhtrzk^B4<@42&p-_l0_ud#tj}rwFg5 zY4Pd9x`s}_uye0UXh5^YCkuaPOsj3Tq;a7ZkY@B)>a5jjX|5IplOcvH^>2%_Ho(H> zuEutG~);=hnsy+J|pKk1dQ|%IUY>E;TpCY7df5AvU0;RV_p8 z!5w2A?iIti6uo*Is~zBAb(xp0_cl9Cs$@Tk4V~~-#ZFtY7Sr?5(?1+1p-u+gT5Cb7 z+QQhA))Y^7ybM~ycr{M?xTkUA#63=0ZQYV;Zl8z7O}|N1b1Hep3Jt`|AdaZrMieDq zTW778nSNnBz(Ng@9>1zJpdq~h_bMbU&BGO{-w)DoYEDN~nc#@3p#k6a*03plI5e@B z=CL$Oan>|WdVBJ4g(DZOT0ERDj8es_)!gpobwn?Xo4&)9ZJ&w;bZRA2V-L+HX(G?i z(KsTnqaH?7HLoaXwgC@mQHSqFJl$HFXNaYFxF~71xOTv6&l{+PYJDD2@?oeY?Yxk* zv}PNT`n%%*Yc+IyG~iAVx5|4eGH@NYWLZ4Cww%W5v~lZt_0rP1OjUnh+h)}kj=XV4 zuS(!4;$l2sv&HB>%8*MpRmB3`k%&di)X&G}TSVPRI5cvX=4x*yd~@kM2$?IUg>XkA&E zecca=Z$7U~QC}1Kx~m$fMri9Iak*Pv>cJ)B#N`fkiJfH}T(q2K(fYb?3FTx;@apUC z(m>UaE91oFT6L)emyCl8&p}!A*m$xlZp(y&!!Uel>NnDLS<-+XTIc+_B9zLH%9QIO#jOd-V{G zYh9gvp@&!JG<;Eq?__*ej%RIvwJqVCDyPq5XakPokq#$5hb68T0E&QjFN{}XZIRlp~h`^d-ooyVZ1KI3}tJeIs4%m zT#896)|0MxuMU&c*`?OTao75L{r_V_z0HFW&6&8;qGXtR055tU6U zGVmuewa{j}dBs>&YoJ)DrKv~yl>d#~n?U%x2!&&S-$n0fmxCa?SF zbJvsZ8|@=6M$5B$OE@9TcC_NciXEDskhEq}XOMhh4BsxX_(tK6U%$w=v9J3o{S;pg zW6yYW{Pl~=)TP)}djLsXI@Kkfg^UxI^VOx;Og$Uf%f#y(^=b>{WSqF1p)M`KCF8`U zLtWx2$vAO2QC*5tqvd2TgBRZ(#bjOCL5sH$ZoJVeYhS!#3FWNfc%K>Yvw&6(s8g5-BGb#|}po+7i23*D<4 z7J4jo)`hyEuByL>^R+RY?qvF|T(+bGENl+jt{k6rxjENDX`R+)u~19%Q&gyYc5ZFV zpnZ4)Jr*u{DW{J&E;TpCY7df5AvU0;RV_p8!5w2A?iIti6uo*ItJSL{{T8yzymY;{ z*=bTG`%!G@gtsbo+LE=HeqGtqKb-G(Y<|Gq8=xnxDV}bfTHP|VhVj-KC7n&0R415L z>#?ddPqmdGsX4teYL>C^ikCqgktdCkudRm+%IQ`Ouuy}f$FFL2Xh`2s_bMbU&BGPy zAHRMP{%d=@>9umIbZUMX=JQ2S*r#~&FS$|b1G@JRPuc)>hJ>_Z<|`0XNaYF zxG2@_e8h0gcG1>CwcbFK%8gz=47K<$d|@GJX`Vs--En}mnk_yWaP9Sk(zNpUv4}tH zZegpCV#dz?ooi`brnZN*ZPuwK@@jh4*wP?kCZ!*=Ab_Njq$6Iy{f1=JYa9b1HTAA9vhPHKzL#rHZZX3Uw%_ z51jQzFW=A@%ca=4?{N`cOLMh1BrV%KVz{2hq-su|a($sXdz+dqy)s%Xyjs$IQj1Dj znme{-{_a?^wY{NQ_fkvhRn+0%E|hJxwydtMdyySPb-m5}Yv_Oc$48p{2_yYO4Bvxd zu)2Rf?qaNbi(X8W=iKP!bFVXZJ`}b#o`vQhc^z?KXBH$rPibkrrdC1*UmG)I4e$kq z70=7;w=uNN{Al(_EUcQOlrGOI!NESvhL>6T@G?s+Wfv1=cEzAHiPrG{>aSlMr=Q|u zWf_kyzP-@8vNHR+j~3s2K$#M}`noF`s3vmml5yg4sJhgHOU8-If$9>sE#u&#h=vcU1I^2|^V zDV0;NtO{8ey;?1Nl(eSw6M~mkcrh#qry<7w@#_~lTfHEC7$uu+C!3;E>#|MgMdgnb z)Zf=?ob(;N&BFDBg&s?teW6S0?2<1m>hL2F-<9K88(?iqmfOQAr_Z`B#hxnGW?b0O zDEV1yYYeY_XhtoqYHOpTvfuC0PGeH#^vOa8kv7m{;bQ~tRn)<|OPOl5G+!GXYmL?V zg%(TeFfU#24OC3h+%DA{W3}5!h_QT-MXWfr7_QCMmgs@E*4`|UC)GIVY&A$aNDUHC z5r3AhSv*#kHBe;K(#lpxQLt}F`o*lqNiPF0E%wygI5kh&658~PQSyZ)ytFiZnLfD; zuvX)wBl6NTsyFXmQSw+(Qch#J)WfD|X}$@C%FQE6Rhvf}ZSf_Q=JwJ&mL^KKJxU%c zN`BVVq6@V&Eg*fr@eJzk85-7dWTIEQ9gf&Q-Fk`*w3wG>@$g;drL`2Lc^#!N53e># zZ5A#{<;FUEp*nj~53kNHsrf%#EIPFo%h1a<`zc8O6vO8cy?h>ONt=(7hgWC!8epNu zjn4&In)gr*rMVO{l&yj0?1yJ?DJHGhzUX@Q>M%*2U21I{cdfryybMYqX^%NZNwcN* zdCivIv3#LAdmWwqlX8{mdiN^zulE07L%mZSyod8n)#6f@)e)r@ORCNjUZ`;!9wmLP zc9&+*8Mx%lYj-ZGIUQuBaoimysU=+)B@eI8>ZMZ~V6Bh0aAXr=xHg+d98uY%xX`6q zR-u>HZeB4~)fy-kYH8|`KIQsa_4jbzfLdH?Zmgqb8Pt+`wPwyP)y+$tQ!llsq@}rI zmA3l2chQd?MHzkFJE&4L)z{swN|CXzdrMVfoK00J^7VC(Ql%1dwW(4=(VDW}`nuN^ zQ{Ij`r1!#XKgLXyJ7i1bbA)b^_nYzP;-jJ)(~m)E5MAAHD3DuS zLw!XM&#lSaL8lwT=y1}KtG3U&I>glq^4WN3bqziZxr^Q8!(jio`5LXn&uf35fpQl| z$NI_RFqrmi|GYRIQtaE;Oq@G3Y&L@#D7SjYzKP?5(R}VuA9$W)SW_F=Ata_4Igjf7 z?{aHCcbLFDi`>=zxixF!q$IJrYFx@G;&|V2Q*{1~k%~2~|NRA~t^+hpB~qW}bDxH` ze7`51;C`EfcAxurPtD;RWzraexI@3eOrWh|S*`!fC!AYdW8eLA$H6pgHq$9`SN{9l z>iX|;|2LcM^=c*c|30_6{=3}8W{-VzzHx64J>j^vzP|lS$MhX7x96c_EAndSFg+5d zJTcWHLx+#6$j*t9)jV|g8Xbb!=ma|jtEP4dW|>8;3RVnz1Z##h!Dd_5dtl2cr|u&1 zspn>)7kqBP*M|P7>EuZlKlR{=7GHg_zOhgAow#P-DNl@jxo@gR4*GP72e;pDn^V@W zFY&B)b;>8(J~H&qQxD9--Z}0d`Ekm{S+Ivb7(CUJq8uFfkeuy^k9}zHiKnXenSeTG zki~fDv%#B;I#HwA>{c5l*G1T-)kezetZzT!t1X&b*Qc(wvb@eFklRPe>ue19>mB5E zHjDiAzVbR7h`pBSw95?Ix?I((44v~jOFOfXA3boiPh1*;N4a8bc5nc&KTSsuYr zf>{c|9R#!Jg8Rzsw%=}vXSZQ|Q_4oqE&mK^S|;0a`DaAame9^Zv&lb$n)Z-?50igJ zG*#r^=65=D1=I~a3B3#T3XRZzet`y0lxx#Nb3uzkD?=Ly%_{2$HEk+nRc$ZyC)IXE z+ZXL%v}4dtKsyWVe6%aku0y*6?eA!hp*@54fsjq;YoTeh(}^c;YAPvBEi{K#I<3&u zs?CFSNug;~TMKP#A&a-Ckj488){}(h(0Hc{S-dN--Xdi29zlCe$l`r0WbuB%I@u(7 zys3mN-fTiveT$IATM2DrA&a+zki|Oy>oG!eXniLLS-cCeUMpnr?nQe}$l}$6EZ)~x ze-WBf<26m1$D3Zr>YGc*;w^)=u8_ssQpn=%iS=M1i&qh{`cB7snUKZ19qn-;i}#9< z#rqWNcS08LXCaF>)ns{nGYMI|MbK6ivUsC}EZ)vo_ZG5v2MSrd6R@5uWbv*=yI;uS z^$1zK_pp90G?&ir8zGA~$)LQx;X)Q~F0^HYEZ*8e7H=D@y9rsmvXI3)3hSvt7Vk2& z+l4INLqZnsb*vu>S-kN=7VlTAQ%s)6YZkISUqr~_tte#iMq%Af$l~oHWbqEcI!?&y zJ0I<8=oX=oI;%T{>`v2z^>wW8VEqy6M1%9SlMC6}S%s|T`LHgGb#<&8V%-euo>=$A zTETiQ*2}P7gSCqF39QdzeIM)h(4Z;uN@s!=fmVe!gGNI~K&L^MLw7(=L+=RL4t@ho zB5zHmO%KfvwF=oJH-vVD4uwvEE)lYLw?dCXuL}*4ogUHjIn*>&o?}`eJ2~?}%VBLp z+g`|W?2mOE){D??f*umG6|bOuiuMaMwKQw}j+7r(>C!@0)jC+)p?#oZp>v^Yp?ig_ zf)}BWp`V~BC6#5H6_bTo7}bRATMo)@ybA431cI#_P@mUk8*^II5g zbs_6_3$!t4M?z;{y%M@p$l^VP_MVW%`wnd~dGj!BMrc7HtLo3tM$j(M;X;<(ypU{| zoW#wby`XW>#ZWi&EHobaRmi#=GJQ_7LrX$yL0dz6L1UrwpzEM2^gQ$-^iOE;40#2! zL5o4FLt8+*3E4Cbf{ugEgRX||fF6Nff<6(lY5WQenK9R9hn9rag0_bCf{usI5gIA` zHmK=BA-U*f2XDuEKh{UFzJql<)~~QmK2u)RG(r}6Mj?y57}k}ru7Pzstb1VH2kVJg z&&GNI*4wb&hxHMxuVL+l`k-lM&TF0bvcDfeKMGlnDVp;;QZuxOkXctn+fvAK z?1}X+SkFYe3c5?kRy>XN4%+w7Ao;Lw*=7>5N?U~NKDiRsjiFtkL!r~4%b`1jtb!+? zx1cYf>`M^KHZ3$i)GB0EZ75`w?gSkKod{hdWO;8wdsN7BypHvAtiPcRldn0Xn!GFF%Io~=msHMdq3KXLbl>#v|pg9<>EE#NFl3W2_cKJCbSh)#_uR0 zTYE0rwP^Q3&td%l`T?4J_B`**(4x?4LRQP>XnP1*-U{03XjeepSf7F36|#8WqD?Aa zX;{1&glq;2psfgv!nzxD7}Nn>3f%@hCS-ZvfWE*wk$fp&c}EDD-@Itc3t4^ZqwRop z0CYUoPUvPKi}x_vt3noUJld~lL*xUtS!Wlrs+NJ)g|>zE6|x*-(asaHDA%D?(O!Z+ z!TK{a)!cdB*`URs)uAn*y`ZC^v!QFCd!QcZJ?J}V@H}}1vp`D-*}MIE(9X~i(0R~J z(Bsg%(6>T1-AU)oX=Z34Xk};V}?#-iE${CYmp=U<5QTv^+El+Fr<} zu{U%i)B#-t-3V2oXP|e5Y#QG}lg^)OGe8SLD?^(=yFo`mCkx5VMxK4n5V9wf>#*K| z_3v0;!}7H`&^=I(klh8|gT8|%YssxMLJJDnp8pxz6xtm+ z96D9Va$E-84m~bp@7-@gUkjCF_eV5Myik5enhu&z$gC@%Z6IVhcEoxh)|1gLhHeqE z6_233hV~g$$2xT3ywbUarq=qF6|!2^gSLbAgN}p#3SBQ`6+8&N4E+Q8myl&EEt1op zpv8rTXf109SuNW@dqc-S=Like6@NqfyO8C07VG<1e?*&N(cG_D$g(XWG*siQinbXv zTF4?Ffp#Wzm5{By3+-tkTk#IsH_#-D<<{witb!IHi?R~5F|;dwhYDHbQ_wC!yA^r@ z>s!#5P}Aah-f5wEpyhntXeXjw1l@%7A?Ot$i}xwoZ$cJt*b;dya|)TZ zG_(%Zc4!~ySm=D{2Izhv%ljhqG1i};DVNOsW)-siSVG8ZSrct5v@&!Q*0Z3ig)Hyg zXwL~*ybsWRK%0E2+&Z(6Rj?4WGPDV_hmhr{pq(ycIj%tKMtc%^8|zolq)X>{XMh%f zR)j`DJ3|LUCqb7&w?U6VZ$Mu_zeB^9$!nQkXt-XNt3&P3flvo@6;y>@hdvjw>HY={ zTQ=9`gqDWZf!d+{p>fdp&<)W2(2LN=&`;3R%jFe}gqDETgf3^ zS2~N3Rkg5?)v^k-DYQFuByoY3t252LAyYQ zKqm`X-iy(07qT3WV|^2AFIpdd)2xzbn_I}@EsM4Rw4;zkJ`n8$=t3b|dn4L|Lbl>% zw9lYA)}gEB70e-IQI>+%hPJ_PZy}3(9NJ&eu7~c!`U3P3^dmIIYIy~Jf)*FDTGl|@ zQpob|iS`$?Goh=n{vCQ&$l|?^_PvnB8?<^}!AwG?wLmLj-3%HH9RZyNT@KwLWO<)} z-op9~G|3vd-}FLu{^l35T3XRIMB52E2RU>;~W zs14d)$a3tDHcrTLoR4+`+C$JQSU-h+fu>$7uV5s!1hgj94($US3!MvH3*8Gn2Ymqj z1WmbiUcnqf_HMsCv@tXW8V6krbwkfW?+e-feh*EtPOddWi$JSFn?a+YBcRiutDw7} zr=fSCZ=gxm%`2E5njcyT+Ca#ru`N`Fj(|>vI-wh&zeCRo*)-mVzJ~^_ms^{mMW9uo z&7i%Z1B6C4WzRlG3E30M`B<;SdL7osu)cuxHLPD_{RL}NTON5PA?sr`(ix;>oHg_#CkQ>8?fGw^+o7o=qG6E_4E2hLQ6nvLR&#)=qTtc=vwGrA-fAa z2Ymqj08PF@?l-egNp@yL(?ZZ{(B{w{P({dcoDN+9bqfvAcuzv_3R#YCg{D^Pq#Ncm zgOFJlKwD90sQQhi+t40Edjt9c>+eEV>4;HzE%ORlEz3jeLpwkR zK*vKD2o2Q=ZiXI)UWLXB*$jS#hHR8;vkO^OOA1*n>q6T?`$A)dEbn<}*9lpUD%R(* zeuDNhep79nXPZsP;w^@@I<$q5MIM88G<3F*t-S{A9wA%NgZ3Wu9oES<$t##e$f7I^ ztpaU|-|j*d`EayT(Jq7T#QGFegT96)-ZZaZI%qy2t7QeWjf5=kE@+3KoeW)!^%m$6 zA&d7KTCb4B>qDDnvs{}ST2{zT#Cp(n(0= zDYUiGwt@D>dJJ@qkmdaw+I>P6?*+7v(0+ub*dni>8CnEd71~nBa_our7a_}WCfZeK zcR^2MeFyp;8nk6z!AwvKv=X#2v@3KdbQ*LybO-bV^cM6b)U;Jz!Hhz~_5QL1v>voG zbOdxZbOZD_^rn!Vre3HInr7?VIybZ|v>vo0bRcvBbRl#j^dR&y^be>G4c#WMU=C<0 zXmuf*#wO5C(1Flc=q%`R=oaV^A)CgVP%qR6P1BzH%?&LJtq1J_?JqP^_H9tpp+duS z2hYUXiS-Js_hNkuzrK}N327)&Fh<0$nwr9WO-Y$u7!1dth-^|59=XV&%k;S z*2}Tpf%R$V9q1cqlI`;PribQ-TA>Z0U7x#c7P1`cU~R{`58AQN zxk9$$TC{u7UW7iz`je1VI^~Xe-dTmL(nX=wpv|E&bQE-!kX3LsbT{-2^sbO~`7Jd0 zPPsO-kX5yikkzs>v2XkXzs(aw3c5keMkUbGdVQ9>4Z zXS9Q%lZ0$-C)&+Iw&G#5H=r-D{*E?$mpsZ`&@#}vLN=Feg)H&`Xvd>n0Ciz~0D1}f z1o{~ovTL4Wb|LF%Nwl?uEbrE6d!Zc-osIQ6s48Ufo=5vo$m0DIZSZcnHVd?{kafN~ zv;{NCsU-U&U0^*!i2tds4YXPZ&T>RS-)&uAM#yI?&WI#tN>UWRtNki~l( z?M<{^s1NIOqw`wkgI0hx5V9OQq8%t?IZi;k5bYM|5v;F4pFwqK=pK0mb3jW$>p|N= z`$5M+e}%4x?t@-{{sH|98a^g}x1S$c1=3nzHWz zo`*h!{s~RBSME0(v>3EHv@JARXrx3Q)U>ydJ%gNp^(?ICW4#0G16Uu!`YzVbuzrno z@ZNcS(+XMMnS?Cw;#gP2x*FE)v5vvIFV>T=o`dy5tT$qP5PBK<2ULfK?vqzK2ecHl zHna`2H*^g2SLk}7p}K?jK`%fbK|exM?3-863@r|=0c{EGDKu1b`~^A_x=Lt>TJM6M z6|!^nzR=Wa{T>>$Uv8aA$gC|wmSZKX8)F@fb_8^qkgd2J?GCgjptrDoDP)ySvVWd; zdLgTHeyA1N5ZVbk2s%;7D!2r?6?znUUC6rp9Qq9!c0gX$oI+O1a!?zzJ+!}&xpx1hl4*McxW+ALv*itL0p@YlUpZy=c!tA7K3f zZOVi4D6>L~LaPZ`RhtW0@&y3n>*_l3p^S>E%|x`eFX2hd(Z`vm$K>r{v3d1r$bgVqwV99yI9 zC1g2{Mmrnr8t5LZJh0LKi~a(33*8mv2K~K@(MS>j-FGXnAN9v@>)tbQ07F-3&bpy$XE+{SFO3 zGOuMWXbGX=`cAScv=Ov3v_EtVbOv-ObeoV(<4Ndk=qqTVzvO-+pn0L?p-rG2g+@xH zgPL|18m2WLjrA0)XJWk`Yd6+=vA%-!J*=N#{T*xRs66j9LY8+yA?tE!tgTo#!@2|3 z-LM{o^<=DPV7(ISJx~wy9`qeF+0l6|GeQeOe}*=Nc83m!PK7QLvb(_T(BsgX(AUt! z$K(}E2h9hq0Br#6C}cSfgieMo7P2RbTcAgTY~rs8*&XRKsE&2$vAK0_AkgZ)0 z>vm}SLB|Q%ioc>=kMs?r%MtcXpZ?H}>E{`|8kX6tE ztt4cTH%8kPI#kGNIR)(!AzN`P+7r-QSieMTIzEpwEi@0boRC%3CS;L!LOTfUMCc-{ zH$e|UuRxzdzd^%J$ZMHX$nq{NWO>&?Ye(A$Iu`5s&<#R1q5IKZ6tZ|9qy2<7<%zj< zRw1ik3204dE2s<|1)U{id9Q}<#`+xe0oEVTCO;{!U}hn!U?H@Xp-r&v0ab)7@9Ah) z2wA_~XiuWO4Sj`m(v$PNGe8SKD+*bTQD{30S&oCzPC~mBx((}N&>PSf(C^UjQ}SBo zf|iHYhjxGtfR2YQfV!XupjV;sP*X?#Za*WmD6}@TGjs%WHgp4Yzfh?u`=;YX=u_wy zXzEjQzmd=q(3;RzP#HQFIv2VYx)*v5`T+U?n*6l9f?1&!A$#^&0a_Q@3K|U^4xI#@ z58WVS)3_gc5&9VV1)BQwe8os;38)R)LTIGSc~H}~LiP-DFxF$Ro`CgAtT$o31M9O` zU&8t>)}OFWd`6yku#n}QUC6p@!MZrs4X|#7b$hIbVjYY1B&?lSZ-yR*UWLAZeusvi znO8Lzv<$Q^v@NtRbUbu{&`>?kUC;y2OVB6K&q6khsm{u2c4$dxEof^Y%dr=9G<3Gm z5Ut=Es48SRo)?;0tsg@F#5(xw+&YVp!Fz_C)&&bPm?PL4Svyh2Dq0hX$RWS1^;1!Z-?SU*Q=x-hR`S|O`o9<=44Hmuu2`wLm#acCC_S-&@-J%siO^eNU~ps6p)D;Nna zEo3>?L2DPX9Q&Xhi*_z_E!KOX7om@#pP(r_^9p8#7KK)WHiyd4QP5e?)zID0Gtj%x zk3z%s-Z}i@oaTpCfwqG7gHD33g6C(J{X`wlUY#NI}D?=MYJ3{+HM?t4SmkZf6?t-3%-hsY>Cb=wMF+DUt zv??@8X!fS;*=KX1VL~IC_7SpdhYOkYXsj1ty$b8~SRcXq9M)H`eu?#0tP@?H=bc%| z^3E+Zds9}`f>>9_x*^uhub4($O| zpworyE^r0Z4Lu3H3w6uM2way%wvcceF< zFR=cOHsY#0$Gk$ec6lLNyFS_u&;deL)$wQ-pxq2TjP+F^t8~1OMgA4*kgM~&vqMWl z>q6T?`wCeFW1;h)>!7NTWqTg_1o~OXs+#JWyn@-F#h}%pErcxZ7__5>EXUbcufci` zS`U8jVf_y4WPi&mm<3u`$Re+Twkfo`kkxWH+Nnae;xe>5p{KCc(7qP3C=*|s({#{$ zLUtln5VFV{q3wcp2y`;mi=kVfN1)fBUZ_vVYMJJ`Jn!5>mUmgS_0YD1_QQGtbfJ*N zyAka{A&d7i+CR|#1(mMPE0_aX3R)Z52HG1sM#%D>1N{x_eb5V7KSKLa$m*NohP;Ai zA=4ItR>is{w5O2e{R`TeLbmoQw7bxrhTg&YJv68*uV5yqMaXijgtoDe<=7SNP_)ya z%dy@8JpsK1eF-()m{%|@G(Xe|Z3yiI9R!^ST?E|(Jqo=JeFIH#Q(nOw&HiJeyESt&0g+yp@D3-o{wB z6|#6c3t7B_u^uNhtw#AP+Koa(Rl8Tn;ys7;O(Bc-o{+`+4r|jbdAw(4?KZ>n4K z`eqZdcr8K}ZzZhj3t7BPge=}}SPvAkcqgD;C}i=j6|#8uVtri5;`InwybrN{BV_R= zxh=16dLfH9mypF<2J5Oq7H@4Ki?&~Mr2(1Eb z0qq5ig)V>=zca6IMWNYr_NxgE(>^xGx(8H&PKU05x}nE~Mrf2*pbw#Mpx>d=UHOWc zp}B=-)v6X0vZ|I7`jcuap{zhl+;w>&@@z%gPO331EE@biczM;l(vd)yT7uK#amOz z;%$X>cOi>+INGT~R^LTJ7VjpkRUwP_u#m-j73)Vr7Vk&2DelYT%^+m)77()fmJ+gf zD+pP$_OL!TKxKiSExMPb*|K z&n9Gf=fb)))>W{sg>@^eyJOu8>rq%w#(D}ZbeWKyh})sZp*Nvks87gdHO+%L%?+&pZ2;{kWH}CmPJk{H8q$=#*W3s_C}cTa z6S9-@8C1tQ^r753hmhr1O32o(jddHe{h;H7Y{g&Eu1C8MdI9T4LRRUILRMAj;XK=) zpv9pzpe><2p}z=O1!qEkgZ>UZD`eT;hrWjfJ(5>7laO`Z0<8*d28|Z7yhos&CS*A- z$9f0WC(z!(?;EU>JetRwUdSq#A8Hk{$Qz>V1RW}5wVZ->iIAzb*!JG{U&5l zrhP1@d7$Nltg1F4i@ZJB{%GT%^ReCpJp{c1eG2^oP5pRY!AK#?yM&PCT?eflZ6D}Z ztmi`43R!RWqCF>M@jgcT32n+Ja_g)@R>7jsYS8A;9?((HSwfcgYUpmP&p_{D{T6M~ zC-Vws7P1N!LR%Ty1nX|lVM3O-1MN~F>$e;2Nwl}2udq(^RGxPPG%vKgkmVSKwzH7s zI2i3Dv`*+|tPex4LSI0?L&KlWYncmL23i-|7TOm&9=ZVPf*ycgf-C3u5 zCZ|QAwV@rLL!mREYoYsvY%gDgK8AjRrtHc6W`!1oR)e;J%Ft2JS|6%nZ#hWYbs{S_|478Vwx+9S@xgT`N@5>D~*y2z?Cw1Wox|zG7BrQD{|YeW8&O zc~H|PLiX%48tVaA55sy2*7LA-V!a9LJy;*W`XbgE)(^4%gmvQQ^Qs05SyeL&*$n2! zx**mSv967E1FSn@JrFt>x){0zdIWk6`V6W=LtmgOXjy1IXgi^yx`X>c$3cIEu7@5J zvVLEN{sH|9D!rKd{Yl7jEDo&!Z6h>9E7%)4M#yrUBQ&*I{|5aX>$7O@3t5gIu}<+) zzP4G&;w=KLDr74*LmQ2D1av0WtAwo5yM(N&r?I{ReFIJMa-Mg3s0CU{$ST+v+7&t! zIz`B`T>{+-Jt1UOy(MH_ehD?bl55jK^9Whq<~*az)c=zOdsaVK=sKthJr8{d z{S%t%?Yx57pv9oop)H^>(2>v?&^6HgLc{gm`5N>UG^mzaXM>i5HiGtmDnfS6oDN+9 zbwkfU??T@~lfIKjnE_e=S`iur?FJnNbwHOww?U6VZ$O_4*);wI4SqM*W`O2_mV#D? zHiz~QvT0PH)1fP%ZsLxe`kz71*`Av8>Pa2~9SVO<96I#@Twx;54^ z*2A$LjrA<77h}B=Yd6*hu|AIV4Xhtw{S51`Sf_YD?`Wuybu@>N&2K4aZD<>4Z|E54 z9O!!JKIjGLBj`tHiVyO<%|dn;SOi)F+7j9m`iqd&d?s`ibQknA^uCbg_#PVcVXn<2 zWbfTA&`LsE!?Bkr~gqDWdge=?k(EiXkA*ZYeh{*3lm8>nHmi`WSQKqF zXmhN4pjCt{%IVM*(B1ewBV>`^Mf(-kCeUusVNi#V)p9A?Z9(Cy6Uc&kb^s|ulJJsiTw%LR%-ePF0qiqfCh4pCYZ0H*39wE!o zgZ7?~<@hJs;4gA*7HDB1o53p3rqJ%t;m{e-mC&8gQ&0{18k)E_&o&*jAoOQwBWM?> zB4qFO=RjT16VQ9mPtedW^R@Fr%L|p7vhR^bK|4bSLnlF<(9O`p(5uiF(C^Ujukvhj zLCZkvLfb<7LdQcFK-UV{H12{PhhBv~g?@x4`#N7c0-9IIrm;LU3fdVu7&-~+gl>i& zf_j8T%A5x^y(DB$3ZG*A4(rcYr~D?bWjY~SJByI5T?p&4SpST56xMC9?uhkZtjAzI z0qX@=uflpg)+*K~us)0ReXQR@Q+%8E(F`pDtqN@hjfReZPJ^z3?t-3%-VqwA=lL6G zlJ9bDdT4%VB_Z4MjiFtkL!nckON1=PtC!w5E_%wUvle`P(D0x0TIPb5fz}tYT6RD?K*;hQk9GlC7xVzum!R=N7VlTIA^*zb z%`RlSuq4`A(AHS@g2qDULDxZ5=y@T_`yupCtb>2a^Ufw@ev6^4E@b^~fi?#1Nazf# zS3>s)S-c*!_k=9ocW9ISnrkyc3kumZ{tRsj?G7C-WI0YnyG+P(+>Z7*+MCeVSSPOM z*`|Z$gI0hxfOdoqgieMohHil#fnI|?gX+-G-||}KhE^0BuJ_K(puM1R(8bW*&r}Z^3#e z)+e#PjP*^dUts+g);_GmC(3JX7P7o^2wC1Gv95%54Xj&W-3jYxtcPPg5$kDKFUNWZ z^aS)4^d;0ZabD@P(ELy~(;bP#kRbdiwV1#W^Kg z3t5i+p>fdpLiXN$19ZQT<#y$Z{+pWNX*Nx)oX(I!ee^oQrlX z+P%R%s%8+f z&KH1IghoNT30dC5&^m-H$E8?r!}=K78~A;Jb)w1hcq4?Yf_b6kg)H*=Xgfd$2w5%1 zqjd_|iks0MhF--w9_?2li!x+zPP0SH2w7F@3R&cB(e_0f3!R7cI;aZ01bqVi3{5pf zUcqcamUl5B%ey+-7HE4xM`Jx3x<<%)y9cdD$l|?+_8r>bDRb*ALRP`T&??ZT(C*OT z(5XU}_e$tatWQBTtY4!|JXK!7bV63ad}x1$Hp03Kbcm4UJsIs{A?x=Rv`5h1gnF^| zLDQ7-3g(8E6|x-bp=~E*ISxcS0qsKQMywA)FGK%;{sj%4I)qYxYvE!Hi;TD595ZM9lgQ|rLlShuw{j;d8_sin4B zs?=q{pP60IP5hiHQy?m=&&?SU*C!-&Qa9Y!>rXd%&AM3)d<4`kW6m*^Ry z*N8qM>fF;?Y);glXe7}AKz0T>1jx=H)5-lBxhIo*KDn2YdnLIIPyr6Um)VbRN-FM7IzGIkBK?Ty9&&$0+N(fj<3n;gZR~CP0GYmBh(-cgiwUGnC+$?CZ;|^$AoKK2AoJ=8 za(_qkH=?3V+-@(Torv}XG7rWRO(8mo=zJivR!{U(qQ`*DtCxW+%D0IAMbvXs=k^0K zyStILKakm&MD7A|&mrx*lxraO0dk)s?RBDm0GZ})z1@SYiG~1~FZ+;o43M>$P1+Ko z%gDWnv_>G)@(j^yL?2PE^JcDjb0EvrK+?t%9ZBviqSJ^jBD$97E}|wN^W_huy$@s& zZP3T<_69QA&P02WdkE19K&EdIY0H4D?bW2+LE7U)za_VssNLr7!Nx>85bZ&95RloO zOjJwmxkTS1_g2y#0W$wyB<-)HttRST=DzeL8V+Q34>12P+>Tet^X0hx_Kq>Ur(D55#!oWkkCYjV3yr zXa>>Oi7q6%j;ImHcKa8Inu$7W<=ir&-G~k*I)P{rkj<2-b6g&MVdl%D!Fx}{Q$^p+)nOe1Ie8PWS%Yn zGOx}d_q#+tC3=|XH$D0-5(sr2T>DeIT>8!H#Zib0BNc zpR`d#hmm^%X^VhN%QB*?iSDA@FM&++3ew&ot=&$}-5AIs-+^ckqC<$L5}izR0g(Cf zJ<@IkGP{qE_9AJ`L~F?1aA)^mTOiXnoU{XgOy6;&eT}qpiLNB~CqxetJx}xo(Pu=Z z6>hgL(NG}E%f3WkC3g;KX8@Uhmy&h^Y4;O7OYWbDJ_fRQyX@lD%79GYuB447?I@xX z$vvIu+eFt9-3??mo+Rz}KxX3u(mM8c+Ga!*K$e5A5FJW1jp!7j3yH2FT2Ax}qF0FC zCQ5d7Ya0>mNK{F5FwyZui-2smznJJ|qQ{7SPxKK{*8$#kTcY7W7WqL$lZk4H&Lz5% z=qE%E5}tBC()xs&l9~)^dV9ELEd&l zqHTdJ8^ehXBAQH8OLQ*Ll|(-wdVuIrAUpd!3uGsS*U5dC+>goaJlK8N2*}!Q24rn_ zCU+RQmE;~o?$P8sYG=|KP0-7=n10V0of|>H=?4UPU}UqJ<*;(*5~7irVyP(bUsl%klFYt(ZfV9 z1KHmF7SX?e%tp^)zWVed+6~CK`;&Gokl9#3?m6Usm$U|=2Y{@_bELga+NVU_c5`c6 z1DU5ofNY)IhumX`W)m$Tx`gN^qDCO|;2EOVh(03fJlw5qPSl@hERcD1B#`B07SU-$ z7ZF_xWOnZ&?Uz6n(I3ctpWF>bc#GaZCbu(?S=)=;Lr9xSvb{5D?MpP2 z=l~$|q0%SIplJ&vfX|H(TPN75?w`f7tzy1ZxDS3WZ5kpgpp0l&qR~W$6HNuOY@9@NHqoU-*Am@M z^bpbWL~j6DHa;UN9pkjEhz1djBRYy`4$%^#r9gIm`8JT9U#=zh7IK%9`#8D3Cif+B z|4QyBo!cCiM)WDUCHpvcOCYl`5Xjn&CHF|uW)YnRWGyZs?RwJg zC2At~4?yPW`#|Q^2K&0T-bDS0MiCuGbOO;LAoE}u(bYtE5d9L!tgRq=hp63t?$yRX z7WocDdk`H&G!@9~o=n;WKxX56+N9)Z<|HU>l-gKxSh<(yD>X#(dJwChZEMACvoYqF)pJndlRuuH)T< za-zXRdlMZ^R73O)qKk=cB>EZA(?owH`V7c+`<{n5+L351Q8iI5Q615BM0W#OUp_^& zlIR1Xj)%J3W<(W4Um-e_Xa>>Oi7q6%hG;p_FNj_tdYh>I1ovPQqHTdJ8$*c35FJW1 zm1qIcH;KMYbRCdo<8Gp-h*lDPK-BRtZ?PFs1<_ta`vGm8$Y-4o2C_5ARC4E%yO7*- z$-S7|E6BZ>+&jtr8M#l9`!cz&lKTO<|01`;;qKKYK$e58fz0Ra$sIxNSaSC#_gHf0 z5uHQyU7`k}2Z){{dY$M~qLL%%710o)eTa?$vQ=O<(GsFdh^{AU1hROaA$pDIBcjen zy4>bKW}`pRD54{Q>_jn(=rka+aS@QMNY@hGMeZ+2TLEM?-Y0j1qr7czAk()q(Oy8- z;t=uB447I-J}Y zL|-SmkmwqscnJ>R5?Oh;?sQs~ScM~9^?MPHf?!iRUfK1;hq%8%qw%;f1Hqss? zdWqaOiIU^ogN=x`BN{Ul%2%;Ktzd>{{(T|Ak zA^H{3t3>Y+b(-uR^dZ`XXe7}DqUl7Z64ep?kZ3v4<3ukLy-Bp1sN3=GOF7X{qJ4oZ zYexWWh~2qYGLzg|puW0eF9NbmE+h9UppCS}Eu=jPWcr>1GJUU;`zDa-`xwadb(!M+ zZ3<-ib|P(0Ak%jckm;LDZViy>n-66A&L;N~Ak%j}Y4-w|zFz>DzTcC(3dr>R4aoEr zO?Cge1DU?Qqzwf!ePe)3-x1_a1=>dQHw(!0oks3bAk+7K(ryDXeGdSczURpOJ&@`9 z6OifqjNDGsTwfm`TM2goGJSghnZAR_od9I|CIXqh`Q)AnWd2=7+D$;F?`|N|_awQ$ z0Wy8R12TPoBX>2B>DzF+`?oES=^G4W`t~OG5TJgVzaxQ6-z;)Z0Wy6{NxKHf^!*gb z^gT@OQ$VKgc_7pG2Du*snZ8aZxPN_sOyABxrf)BD_X9G02LqYD*PFzqsf7;~P z6DLnwFmTZDDYf$_o-%j-#L3fZr_G-;8Ceeh$LVRQ!m;GM3K7Xh@Jn zsrLeUR_lF>+}YGQb5_=f@KR^B9-Nhw$XxD{)J&U$aL4rYzFu>uwAtczp@|hqL6^IP zw$bfds+@R{Bo;~aowJL!xV>a~Y0_tT52RGu6lojd@3s8oqK$6fXnBXEY2H*~d@yZ1++A(aSyCseZFpX6@yF)uHuZuPf~RMaS$Zvu6)hlcj6c;Fpc{rQ%vw z@i$NH9y+J9bk2gwCt;MN{d1}g(*esjOG=gt-TP>P(uXbID%oiHzuQk4e+R0+4H&$! zzgiFeN*6J_fkRZjF-KnOK|Z72#H(`Bq4gl%i|Ta*V6IP|a-#KHj*%HsFJxqZir3^A z(Rv~A-Bi3jN4wSwiH}h6x*Tz>2k~r%2B~~yjyGB_q<)x+H|40;dO`I=Reo`fyw-!f zELF36NOvAzW5PMUES7p9UrcvJj=0tf`eK7;b&fAu5Aw1SE!2@!J9{2xv#oV2bTn_X zyi3w^d1km+?wWHHYQ3NXHrvW_9M*cF_=ambs&mA(UQoRatQ9%#Xg$bpl^n=@>@}eF z4<^f3le?T)p1O9y{>SvZ2AkfEST*J6=1_V)E*rpW=||eF?ML+7gr6Vd=lW3o zB$REu&z~2`qvZSFDW&b_`H9DZ<3jD7C*_aAkH|^Cd*4ebe5bn}r@0QHiwU4q>Yr?=L=HU7Hl zak(#2-T=SX_VYz_w$x^Ac7)ebyO`cK?<`L~*1YtwE@j)i%dTyn8y`n)^DaB*Juho3 z+vZ){yvrRQzVu)@M+U|Gh9WnQu=y~%p&YRFYpVCh1x$Rry$9lcJm#))gzG%5V=EAz#ULUsF z_Pe(IE_b}O&AYb!PR4-jRsL)vUTX#CuC+3ToEDFtw*9Vczsp@;zG%H|zf0#>d|qjr zcj+99*CEeQyml2Dd+~a;F6}+vt?6G^xk5g*Mq3|qp*0)MUmv#G&Y5lJOdn5Pw#~b? zbEb@ewsU57|ML0aWo!FLYkb$^<^STmbKhGkC8oB|+@#~^-~GH%OL=y>dcjIjqiHAjC~MVYwcU($9e^OEV+KV+!ra=$6Q!fyX(VN+q_HXiH|oaeN0H% zHt*6k#^;UC9jUj?ySCp4jmLq{BcaLMiN}i2;vbjwvTfd_`DtxlwZ`{6udAHPf1YxE z>_O{lZ++Nm+wa=;yWH{SYmd`gn=h^L*Hw?peHo?r*!KCUbnjUopSf9EKb0jL_KFpZ z@^y|qz?QEk6t;b7Vks!{g@i(x0>984F8>7sNxzU#2o3lSvp^WA8X6H>e@{Sbtz$lTB}T(3>>5)O{vH*6w z9y@%CotTxcp$j1l)fTIx76Vm8z9=q;3{sJ@w9UZ5DpH+NhO5Ymw9UW)=;ecZzK>Mi z8jT3~ZqfmuEx^xpfeyEp$oG}*gmMp*yP_P85^_tbQ4T~o8|5IBOHd9*c?rrPD6dC} z@1tCDFUnykpFz1B%GXeiK>04p-BJDvC3G(-#aD7xqU?imPn0{L+zaI}lwU!)56V#} z@#Xdjd{`o1zd8oxB9voME=4&GWj)HhQT_zwJ}7^Va$l6sq1<2iosy&q<<~H}4njF= z$0Qk#auS?56y?zeB*|eY4@Q7TpxhS$9))tR)05;Fl)HT^Nx)jN%hgG89Lno&Ns`GZ z=i!U#rl6GX44sbhhbU*FycH!>Ecsce%NN+4i25%={rSL`ZwnOqC!zjnsQ)X}OYg)O z1-~!KxhRLDoQLutlwU(R73F-Ci%_Bumt2Ih7UlO)o`mu`lqaM78Ol>oK8EsCl+U7E zgz|SNzmD<^l#5Zmhw?O(t5JRfrF?(t68!6d@(h%_-fjIb2Bq}FVJM{^rlFL6I0>cn z!?`G>AFe4%fVFLNw*&vyocLs}pvSx0KpH9M6RFX6X zRGfT9+CNF_f{`yRN|LSt6(>k$plwUqK+=YiHj1=yq~VM7LtCU=QE@VdwE3i+PTDs~ zyP33GNV|_TnXBSyaq={2GH;FcDrv8g_BYbrC#^?2_pet##YsQXb|7syX_cfMMOrm! zr;xUowDU--Bkc;(>PfqYv_{gJNPCvF6{M{st(i3W?rF(0+kvzS z(ke+CNm>x+ja=3IN6!B zT}j)6w6Bo%RnjJsb|PtWNxOiw3rV|@wC|JlAZd@1_AF^HkoFE~ACR_&wDuc#zik;% zNz#|J{-g~e?Lg8FA?;YwCX;p=X=jkOjI?i))+8;=Ji?nx08_?N(84^%&auR8a zNIQqL3rHJ3AxZk^dVg3z#mPjV&6GAJpyFg6(B?|34X8L-0@Pb+X9ZN8TmrPI(k>6E zIH^3`{TmrjaWZns+}ZQ`&zySi@N;DYuc>N3%IVq)-Uw|TK zC8PAi9kAcv5y_8Jiro784H+Qkq_owq(dtTMH>Laz6n{xCCdukN%GSnEuED+YC@17m zF36)aMipbBS(!N+**emI6%Z&({yO70ZEuj76|e15mzBLDn)5JbuC4sWTVOuAY1Rtf+S6%sGPxRUbO7X4>Qh)2dGzIAmZo{_sTY%qb{x z{??34j{azkXEK#NlXAIVZiIW-y^|#`Rvsw!7R;SqTfW1gJC+|juXg6_nTux5IiY+E z_WhYP)A01+L-;Dk2kFfoMXwH@HsHq6D~`Y5;V1r9ckNwwB*_P$pDYXUlywa#8(wC` zuI69LsTS{Bh-pgF@2~;o{iYp1uY6AwGv}2{eMtGv<;N)jbRk$}fmMcsyJz_qZdl%L z5G+C|59~pqrA#QZYdNAq{td|t!DT}>jigaGdZ10#<_53;J zyUewdl8rY$qV}UJ_AWVY?+3;mb@ZwmR!x7Q1TKZ0d{ zX-h6t^1$2wbW(a9v38QRw4MBEpZJesrGJgfv+MRG0BQG$Mn6>@mX7b19Me-0cq{1F z;YZ%Uk?i^_^*i?soNjm*LAd3}gS^qw6LpDd8~mUy!OL4I;z&87u$s6bwG)*m4v0fj zao0ImHlX+MGaNtul75qyq`E?pJYGzeNLO@2xiiY{D5YO93iY9-WUNzi1^yRQlGF!O zoIFL^uSxqOX|I#k4I{|fZWvH;GKe&Jqd>UD$=;;luhR$GEYjwXCJ!i0pFE(nw!@Kh zqg4h}oD`g?WfPVj+ZnU9H)d;T3$wKsChU7%6r)#-Q*RL8SGhZcRHeW{qN$2#E zwsg@qOO7QnBBbl&CG&MF{79e3eBB*CG5>nhJ1f`b+|V5U2dH-lf8b8^49MZ* zIXhl5l59S&L48!td={Ui?O6Q$3Xd!OmnLDZ+k-J#&!x|5Z<>hro)Aptk|x_u`y#n6`INQ?WAQ~v9w)UglKvMx ziyCkEM!p_A#ezF=E_oKXrAI+6GIZ%`snx{er%j(be;WR3XNwa4XFXdKSjR^rh41yd4Hz6<;Rg;G zF=E7S@_$5(?)3u)?lx?ovgBT0mi+jE6OLZCo&5DudlkCZ*GezPuLAe_N{pLpbL2+0 zaIgPExLdnQmCLz@<6x0|RZh6ktI$1s9>(uX$o&>45_yU0LihTuK_48gog!OEA0Bij zhe56p&pPBKMN9hj5+|cqOZp~4?iV;A$*U!O@;rGzS)QX;A$_Ho3ztCd2XcPEOVqaH z-%y{yD%oKe=d(+&Cy&i@s*$?+D0^4zs=`eG>1ZzA~&upTye@yGkEB zB(xasd(d$!WUi4L241op7RujP=z9P%?QLIgu|MQEb~a>Q3UUampgxKBkC1t)90GW? z)E|<+DO=-H82FJ_OZxhOaVBJL=xcIo8_z|ul}E2a@ydAa3%LvWnP5x(A=9UH+ejH; zA${f0w<+Xy!|>8&7V5CcCwQ6KN-rW1sSJ~>@j{MmYy&2eC%fEsQI#WnYy@Di!s$%kFfHT9nbTvSvi^sK?FoiE$Y+e&!00Fb+Nh-^5C6_KX(j1aHRBC-@4@C8|%B5?e*eQA3cBS(-`K@DgENJCwzL}W_1@0xNG7y zB`5Cr9L|oIsy&K!JAKrLue|ZuUN>&G{GDg|{s2e(k6~91s`5GkVNF6g5gs2(_=dgh!d zH4CRs1MEMb|G)u*hM=roIAwlq^%QLGC@0RIHhapvQztIyKV$vrJQ+`B@l4fJuG=%; z&+&*fZ&*)h$#Z?UtPgunnz>-%_gjK}!#Y1vc;TiY5`7=+NTsuv@m>bmodmTD^at%JCx<0y*z4xDZ z=xh%`@su_^5w?4}+<@hI=e<}&TzX*VrQ=GAMwK4>h$?0lo(;h$afa&^m?P__8KJH-u>(qAN=*^C7sl#8>fpH4< z(@{OersP$gWvp!ge370OJJ!?suvNO&UlO;}CH8)Sh%=>jHAd7D$p?=9+ST}Eb?9P2 z*2RK~We~{cu0i{5K*jnw7o+`zw5KTdYtsHm+UumrP_VW#6a;04!uc{3&ex%Ez7B=+ zzvxhqS-+ORU|660>eFWCpP{4B%9SXQ{=ujvRLtziJwb?GnhJv8t zKD+N9BweX(KXw<41no#$Ib5Glf6=k~@Y(nXM3PnD(rEoo^#67TJ?u-FryYPma2O51Dy$heiP92V$vFfJwk^HBN?I5>|rv7hU$c=(5-4i!OU| zrP(`Y2yYFV>;kgl%Wp2*Ywbf=K7p1yV6j_-0sCLM0j|>yxCw@X&vHL?g?lrbmlH$(nezLg`eBkvH$HefA}O`<}-h}BLc_NaJ1>c zrD$E3FkAY%vYkh?)-!Q?yt|!Un)ImLzFT2(NkMYw_P&t8{X(x+7BW9r?;Ew19Lv%r zOI2l{SB0^5C`x%Mb~wszC~=ftBANRtO6e0EsC9|j3)se>ARB{%Y>6_OY`8|dFCbf@ zjP@#NvP2o}ebPQA?K+GS;g%#f2BfF3*0jOVE+C0o-_%GP@VO4)j+qm->z>az9DKsgHKOq6@0oP|=h z-ml=t#)8FSQ339aa#TAb?~QU) z`+!l7>JTu>Q5yt|aunK&n!QC&r+`t8f(50c9MvUYl%t9RMmee^V3eau14cQjYrrT+ zbqg5fsP6c{$l#{}p?mrXuTF?`9DX|LMa^lu4utYz4Ewp0!)zm<{FQDQ?GzqsPd78ApktWmI z+O|W|O|D}=IFylg1!+2|dn`S?$I^#o2CrSaw)RX zYt`^9cLqoskvRxIH|Y2RNLrr(Q<1}Uf7}>9ecBNEyNMBein6uaqJ$&A2JKI+WYL#9 zqqp-&eWpnCxijV60y9PA3cQxIbYHZmS~5GdCH|YDb47Hgb45nT_(-kfb^v~4ts5KY zBQY{1-(yh9ngRL}yyvLDYA##Y-l)r#fSz6=eX=h~iE>Z;*p?;8wk$!#iOdh9eLtXL zy(1d!VbY$XoXiw!`!Q*MC#@Kx#M*WXs5q%7?P}8OiqO4BGQImBHbCp7d(Y(9N4f&Q zXN)Nsb-5#S6VT)(JbC3_7VZFTznsgWwDHTrZRnuUV$@c=cM1R%6XsbwT4yZW6rjU7kd7qnEPx5N%bCX*eJ9&S*g(v3gk$tdzk$h}Nb_sde=O*LNU&`{^zR30L@aDxe z`Fg~Qte(#L`O8>OvC8a^|K&CF#ebrEU^w%6P#wiZ@-Zy=Xp_8(^YqAwNd0N|`iB$q z^++^Xe@gT8NQT=N`TjSyX5`KJdc+I-;&zlDd`T5(aa=uA#^ZW)yd4)eI~9R zd3rWf895coT-f#UV`k^;k%`^DNIq8P{k3799@)v-7afZKCA%+vV<@)#+&pirG7^{P zxmTVZ-Q_hu(t5x9`i;-mBj=^|Me;E+ABUUd>FKR9TjPIuoqPRbo9FAnBUb2%$6@b0 zJ$+P0Mu@zgoUrK``FfxlddlICjBI)JQ9XiuHSL}F=XbXkGG6KDfV~$>DTBeTug;`g z6et^#vOG|Fk@9k&bR(s-$Vfd%85t96;jeZ{ z|LDVVWgxdNk`XJfgO_!FK1p17^8iGqT{0TAiJ4!DOh2+VQ9tXTM~1bF{Ez+`d+sCc zwFg=FapKzB6n^(_?QOyddhJ5;;cng1*DjXxIhD2ihJ1mKflr)>PhO3j-pWgU3w-zx z{Bk#6t$kX2(1;Zxp-+qZ)H4bEU*OZ?A7aJ+6Id_VMML$C zY~j=5Kk#)UC{(#<0txwQ{A@0}V)PoBj2sEy|LZ<&iqqYK+6C#voz;ggV)z^_!nZPfju0js`gsyG z;ZTIU3nH)wiZZa)n$Xes@`lePKJfF25Bi_@EU|qnfb7Sz1s3}B?g2{A|CI3$l%D@7 zW4Tfm`ZV!zFo16z$on+0{N{0wqWn)2e*iu5TZ}Dz26o*)5zLQ${_lLYxX>qN|Nr@+ zUwy_aJB55o_HG>Bp8zh#Pl!1lL*0Xe>Px}r5_sjmYFHA^kKhQ^yTDloWUA+`U`ZQjrl^X(Mfm+O z1W)hywx(9T#cBB95ku??p5*+#fqskAzeX47XUfoP1<&s*gb}|AoZsaeA4|~LW5U^7 zX8*_*&hI}fbbinIZO?13#oLxxm0$U>8NL?laCw1maT;5J=e78_z+%K8FIjTsx6i)d zIllqT=X_beRp!4JydF>b@+9g(ME+lP&i`D;-nLWnzxx|^qnlsY>Y^jh*y_-Yw|sVw zAvf-XGXus%p|h|&y(@HfenIK^XXGuh$rL)X%h~yD*?|6cPQ2^=x9JK@XZ?M;FJkBm z{*K$1bz(1cJ6QMY(EqL9ryHJrf0%t9#P14shP#41JGZ-nAiFEbvvRvD2(r6^JR7&W zf*`vq$g^;}D+nr1&cQsCXS*fI1pyT&a(~@IY4--y^4b3Dko&UF_IP9TjOJc&}>g47~{M5)N++j18LdWRl>=VO7lq-`6T&E7V@}=aDVdO~3 zU&AocnU9WKcD70^J6ryYh6@UwRpd35&lk|(Tt-_jJ3Ccv@~M&_pvFS98bGX9-O1Y4 zh+-MTg>1*cXO#roal%R^2l;y4U-hJ-uuLJ_DjLEnXj|Q|HFj(Pi|1Tr-#r#uUqFl?p4~P$SSn02 z7651=jk(^6*`~;BQ|g8=QU`6fqpw*-hONPNc?|YzE1gY4e0WY7ggjXO+3hY*$;owS#+P(7ILKs+9qWO@UG9FjU%o#Q&2+@R=WMXWbCNBklu5>snU z*&fLD9hm6^kd{mY48$F$t}&uINV3wLR?>YmMFZLa2)^8!8!c2(6jjB)^sPb}S-uCX-O9rz$ma z1RLjAmd{v)uU?)4JEEpp&{IGZyRQ_?QXQDgtRyp3{sU{ z)pzfK(|J!_U;xWOT7hx^$_A7o(u@+%kH$5joPoM*_=LK zfqFb9WEe?=KJsMDL@CvoBJnvNvpwzw*_5Nc(_vUYt8|s)gx6LOQ~BmW+4`oa9}hh zRU1i#S0TZ8q#j%=Af@etl(xtQ5Oit#jFfNS>X)fc4}_uB;wT^so0oyG(ed0Fwlvoo zoQTet>U!qj?@gL4XB@fFQ4Q*%>i`z}^k^%bI?uK`ni`WsB|T~Jwyg$3OFs+xQMfs1 zR!uZxF{Ck9YDclI!XX;DHbp*2B^>Iafskf1bbvR`J<{sFrLKlPEX}uUt{Xq!lMtX7 zmrX9s4ptTSOgR}f!t~VWsV?>*j0jIvPIvm4MKkp&4!gC4=B6R2@JY*l*DxErtD+q1 zqkMZ|@$_NLuemhsZ2VO?<1`ymrNQ!oCrBAH;N9+hU(p<#<; zsOy|b=ZG{536l1aSQ9GD#$t1l^~#*O1!1wJv&ULRRE;jPb>uY^qnX_Wj%U*@b+sS5 z1;Iu+)}a)c(45zpyPkruJ27xy3CIsC1rt+;Tr|YPh7~xIa=!GmSLCEUZ0$>S@S2>}6!cO{5-$7^Y&ZB`gDRD`UsHeGbPn-CAS@rY|9>2b!Ib`f7WJZxLiE%gUVpK*gHnAifskzJ$gL65HQ+%1$<=qLGfhqh# z_j6nN+G520LpKo_+}JslO#3f$sP{9MFVq%)dj7Q8 znI5iOo<~r1J*(0}=XE3`+fTmYh#qmdC1A1V8BjUdtwdH4i&~a_#)l^9$w)b_(2wi& z)=VQ`tod>uB)+t9=u|Ru95!K3kRHey+@U6@aqq%G!{b)7+CQ>AWx9=)L|J^r%FVvG z8S~X`SEinX81?ApsnHBKMxN>Rrx^%&6ee4u65H?|Zg!t@yEDYp==^F+ZJpIMY#S5| z(-Z2RhcV8}q=y|;Si&2Eeht%ej3yapB{Gjh!)`#m*;}rNDn2NvwjNB6Av+$Cbe?9! zU|JD{!AXrXjH)I#C^}gYVOkTv$jOK`}BB_a%vdYYC)l`QeMK7D+ zWu1o*`k^rnfvFe&S&>YzQjbcrw-K>W(Xb^Av?k41X-FmYy5uyKwNPNu!DUQr5s2l2ptFYuK4O5uF; zN0eO2XM-mf&ZQMt_DtL3sK}=3ph9WJN<-YN36&K&-OqZN4IkDkv>qQc!)g$bn06Ho zY0qz{X^%v7b*js8q|w8!gO|)foDk1;VCo33GB2y82z`boCK>9`XPpxKE6@a4ibZr7 z#44M?*Zc&P=!{5Svmm4>#ISnDj)Y|(Y8d>?==O%uVqh)e8z7HG8cT>vt;fSv6I7Gm zjip9X`Or2D5uESvQ+9OXBgPdqf3Q%1R#hHX`C3TpjS5+4dUd zmcv={rOqBpEAO96zWx_uM1&qLwjGBOIXkb;ssFcPM1*Nz|79`e-OrcUU0Nm#Zq^rB zO%@Q;uC|)Y6x43Dn#>c_9<-V)8mK*MHJKx*t+ZN=)!s!d%w@3>hJ8H0qUBpxPMOfr zI#b|&E)HfSa#lDyD`X_Z(+okJ%@D-jh@h^BPJ44j|~#_8BRj2SV8CDJC>oEGD&yI;Bd} zyMv#(e6jPpYdA=R{Wm%rY1o;2f;aKCKWx+K`iaHdmlSb9jy%~@SeEu$eoOS*5R z9TG-gwAH|}d2fBJVP-t3cTei#)HI?J+|p>l%%~AQTcQ#(^G@M967$1q%n7^B>)C8- z*p)iWnL}GjI0zWFtI#kTJhG-V7-^DmHhY|JfMl~Z)38^h_0TG3_;?H$RH-*=ovui# zSP_L@@ln+j8LS6C)NNQdco1TMoQxR4i_{5@zNZ!7gk*#vf8&z z@UqVNi_NP>&$fiX)HlYJ=D1Riirdha3ri=o&sOJLe%O-SP3XnR$$~b zcpv-+(;oa}+Re}SX-1g5F-g;|l9~_=IKQE$J(aQ-ibPe`So=#yof|tttHP?Z>?PxqK^L^!~ZkN-_3v&n~x` z%oNlHSWV^$Y9p;CvjnyAR+AM2wMkZ!8G_n8)NG#QFTjB=?R-{;yB4<%g3;>c7D`1$un?rGB9deShebaig{{!nvyhd{T_D7a)l;>qN0ve? zu$fR&t?C3fN$96>f%B*wai!CHSXvwlqPvm656S{I5 zbD9OUyqbATDjaNR%oS$F`Cs&Y9y*}O-O$cSuVsEF3ueT!?pqpU$aYTl#nU*o>bdKe z#-2L6k2M6#de>mm>M}aiEVjqArR3Z;|^qpWHVaQ6-gBb3-iIgvyGb!-oXxAr96pj`%Vjn#3es6jU-~Bd?YBc6{@Z zIg`n$)YZOek>MHVSnIKs>YSWcWpnPUdPtF`y)-L=E{QVzA56P#ziGFapV2c9-x6Yy zrd=gN+Vfg5?U9tU@}cNjIn`QDNZ8UjF8$uBoe(+<35@P6Y8(m99LcJ*10pHOe?~-y zMXa?M{OD|gmhCk0k1{R zApXzBh%M8@{a=qU?|!~SW}AOU+c_6mO@m6iCJSn}T21B&Y7bgXW(jJ~T1{3A z)K*%p#%k}Pw#qJ=RiOAf8qKeGZs{r~4Xu>0>#u#4}Jo;2?Wk#zW zA<`qv3Y>3zEtbQDA9mEZ`kJ19<*>o{^iS!6Y8@lZ6DGQ+Q(tLifli}InH%f!w$jN zz-kU|ApR(Z#hFp8Vb_E2G3dZ!r5PN$BH3a^bb7@{Rg)VOg{+8VgK^YaL(I%bBD}or zS>ZY}u}d>@U?9^>42B5QU|m|bVdLTXL%HT)BP=C8BqYGdOk-5>mhOWuLON(UhP8`Q zlIkRYs&TJ5y{0=BU+Y8hQPY8+^#Vj&JV@%LF;~2+q?WZl@K=LA`fE zb6jai#Wc@Ns52p9n6Vz>V7*M^im%OK6vZT&*M;^RRc1NVgsHML?eH>_Q>n*I5Nw=d zSw1sX!Zh}L_%!z{_%c9#*a!ljV~)v{e6j*((h4l6nHDkEsYA~Vf*SQfLn_vK+AD1M zFzx1Qd|~jkt7OP&6B445VVvf-(zK@{bfnIw(qc2*=p&~NUNZ-ALc(>E%#iKqj$-Sw zc1rLM%1n%XUZ@ok6-h~MGlveX$5Ep*GV)SSL-f@2Hynn6?d;i=ZzVOXX_2K<PaQ1HtMoebf2SYA{T!EQ`O|di#k_~rWDJ2NIS0kE@ zgbYC(&Jc1|IGfRV5}13^(wF)w!P#|Pr)Dgr4po?7v})KK&a6GYH^owtJXk1=jF#n- z)ThiMmE$_Yddma0 z*PGoY&Ma&hdX(PfcuTWQ-na>k>4Q{)gQ0JuY-;C3b?X3H(oHMQn+_^w-z{gBHSs*- zNxi#O7rWIMxuttwWJWI{YzE25K-|NgEguAKHVj+#U^rj3nozb6X<%=Kuapi!drsL@g+B^v;qTB$Jsn$1a**%!)s3K;q;v*DjclSEJ|ZK&=^&G zd2ps5$)m+k(iLqE8ZGo?R%Gk{NJ^d0h*a7N(j3y@bF@BAOPw=yI51v)9^k20`w~Kf zx0FnIZ4P0?(1IM|BXJ{qMX>o_MzvCChL~%%pIi>#bY#R@n!%3}p~FBm1uHTvH1d#zO3PiOA}j+LUz8my)^von(fZ(L9_0iJ zHD)1lB8;tgxEhWva5lx>23@71GN@OaJ3I11oRN3?u8MS&0Y?(1Ekh718G>XaL#W6l z)MN?r<~a`Da&PDN!^t5ZS9Kk&;Oi+rynikS_wYOD2IYRPhx_pUxl#4~bA#*kel8jD zQ7%I+>SG;pk`L!MfiLN>x-SlK7w8#9^5IQdcyAf2ZF%#bg{Qa1TvHEM zkLD;OB-X0lr#FzC8?T(=qSG{vJlVrQedH$7?boKy&?FU zizb?}0MeK%HBGFm*(PhLOFmX9=2#DCJO)}%rP!jf>~O z839r1>SDJVQE|6)?~A%eFCz7x3P?sa!aU)vMSD26J40B^c8$5+T0-6JFvk7<80J#i zA$k2QVKSH;e&L>-XHZIhcu>{#;D@UgEM`# zQiZxSiPg;FsDn?(ecsX)w~}B|sc?9Tx-ZO8x+rP!9`b%@jQwZo#s5%Y-;!AmX0taF zNme8Wv?d8;r6Cp*KUM?lu5iUSXLD-!bxbFp?BEPRQF?GlVGb_mqmH$B6OLNj*ruEFzh{bs% zO}k2lp2=^eX^%v71+L5K|3<58*e&J64-K9p->jo^pG~D2aWhOUD9fD3sw{+9q#+~X zna^l#hKS}TXq920nxc9XV%WT66=4~OTZO?BEB1yJj6mE8qbeTmzKTRngs~M5SC@)h zw+WCv+ErUlbjE~k46`ToBQp)ulNssdT;J9fS0b7vEJF}&8G=~J5NdKIB&it*@iijg zdMzh>S!(>vb2*jsaxO=FFjhcL5BA~P+l{Jko*Qg}fS%{=%i-iOk7oIoa~&N`KDffD z73=ZJ5%!qu5LuBkgk;o3>D9$2>H(ctl8)3?+-W{h;@)oQv)@>4(_3~c_j61jmo*b! zYm0G}UhZ@?D~m_?K$ZXU(S|pRhFv9smcnA zAXTZ3sQ2kzCFGkYKd6gt4_NGZ22@V&dB+d8vh33n*+%??E;g0vdyJoy>pd*>FAYnD zX~trpcX{55Sx=B2$Qn$onr#Bp9Sl81;cym7>(&9ZB+AUy!r2!$W4^i_JfU%qQ7%Gh zb{ZqM^oo@Bke>U}j6*WEk#`Eu_N8`jl??)ByV~llCDd~m&T_mz`a$2@YnTn8>onmZ z!5VXpzZy1k(15U;z2%Ci;v<4;>%sH@vf~j+&kQUW^tyC)T5+9CZcucxB9gQwevy+A zYs#eGBjk{Z!`EX)%7KBnmI(K>;&u~WPsJVY^>re6GKKS(A*MN?gm zy4w)X(~9U|LZlfh4Y61gD$It?v8Wz`2z;G7w$|7Z6GF9CF-bZ-KJWT{NcCAOO_(YR zb-0-62C2vLh%`#D2cNN0os;u0%{_463p`)GQaJy=ChcLxiql@Ip;-jkv_~7Qrd=h2 zNPa6#dnBUMvo1`PwT(kg>@fPmIe?>)_g3wM(5D!XnLA4z>Q$UK1)DTvMPwc8js4bAw~mJCq<3*PUJ)wThWLOqc`Ka&x_J1 zCqY+5L{glY9gzc>*fYMSD%44tOf%AJytT^^B=!uUEVqfM%t%O5GlbGyLQR%{tG68g zwIls+u*nS|eve&_^5H#pgAHhPD4oydL|*cf1=l{~90dT#ddd$QY4?WJi8H zAatfgqXElqrVDgrrYRO9c_UTEza+%1)}b!>@cMtnd+cp7X7;MKezZp)*|C~;hhHMI zEq$xqYBH2?`@Y(0vU;F)tJP$xp!T5EWZgjRS*yt$L2aegWQL&jE^4dn=2-=b&s1sY zSlT(3*_>I4q)~>@+VZBWWJPW(v6oRJMk9j4%(V8kKlW6d!Q_wTn(r>Ll(OR`g9|s> zmWhg0mJr3UAa|EoN@B@rsMfOH2G`<-K}y>Pi#53csB1w`Rb&MHkm`GUdd3V*7Dv%o z*qC@hMXB22Q8w(7smdT9pO4DSy;!SypRWBO-_$DWIWHBm*k=#Oxo4taOb*yQ^VlYa zx(h4Q_ZUA-)q7a#Ty#PgP2Mt`Na$Ujw;~)8q-L8^H+1Vs6Kp-@!t8+1nCG_U;Fhj; zao%#WFEK^eG&LSMW5zwk{3A5;R+mvDsgE))8)fW6=;7d_4z=9wtg=DEY=^MxJlkbC zgQ(K#xoKeg5Vp6^>t{(ggURt%!>;#)Hb63XE=|&kkBA1BtOwH_h{q$7OmAS2V?}j3 z$8|QvI$06x4bBn2$Pv?_;^Qgq0qq`!n~7aok^=*oW@3;L)y0+Ow4(hP^4%P~^G8qh z?yWSYnZ~FRmRBUdI`NjdQG*wMc~>kJEgF3l{_Ty}(oCcX}qK4!H=Kwl(HIm-dRB zw1?eY$(FFtS@A;*U5-^Uh~&3IUuRAd(xjzvs5x&bCw^#P!u)z$Bc6voZG^G74rTE* zsZf)KjEK6>oTEkRQ6h90R7F;0n8aDoQIv7SPgzl`FnD6cVIPe~rOpU#6pu~c7BiuR z)K{l|`C1dX9#(~nx7s2zHC(DR(iMB2DpddSW<(eal7<;;y~B&5jD%Rs5JY!|P?JlL zxFZSmNJ5HexO(diAbbbB9Ng2l;k9OO!yAp2A^kmegX{GU zpQct;hWrI8&9#oyrks%~<3AdSvL(BfcoEMq8VjR}tv&U~~tF8av^ z@uP$uR+AA8Ub)puQCoW8>cJ0!GytT*PeFrBT+~OJh*&^vywzmJqBhBDvUs6354Gb~ z$@01M^Q^|GO(Xl4usuX+#$hT}yNqQ4`TCKpWzx zSMoOgFIDs@{ukRFlYim=u1f2Pzl34jt$;RC+91-#$=}IP+7UpeZzj35K&EdIkm*}S z?o~jh?-tS?0y2Hi0GYnm$(6sdXZk({GJRd}O(W*tra-1|C(`zm?;%nD4gfNJ$B|nD zWcua3fdc-vgPxKLMG(kIC(Tz0UOY0WzO= zk^N8ew+E2vJBZw)flS{-Ak#OWT-lFJ-zB8o1Z4W|1~Pq5lKTwM7Mj1`0hzwPk-Hkm z^mWI)G5`9?d{X}g1DU?P$vp(f^c@Lg`eu=P3XthrO4|23f*mr+`e~^FXHW z4RSvOGJTyox_^CuOy3Sbrf&~&_X9G02LqYDq8NnOtwuwj`~Bv_YipN!l3F4kGO^(vBu=8fm8hSa5kyr)#}my5vW$O|=sQF|BD$04F(C8#H$-m{{e!5ai_7%}G8@|x4I&y1)J@0a z!9){*%tj56_4Hz*I&!~D+D$-a<6d$fC-+6t{zUWvkhN%!t;DQt1Z1>rhz6582FN^} z0AyZGB6l{?BBBe3E+@Ky=x!jh_9W3OL~j!P9muQ|mpJM}v=fkdwHuJdu@BLaL{o{r z24r?mC+$KYvvC!6~Oxhkq2a$Um(Hx@FiM~yA z4bg2tX7?eYUz7VsqQ8;*57J7|F!%>#{%uRzAfm63TSas<5dI;ynWQZSGJW47?T4h@ zPV^YLzae^!=zXGgSmIHEjqX6^-&R0oV-RVhNjsEi8o3LJ&Lg^l=tiP@h<-)%D$#pH z9eTPieTa4;8c8&PXgblUM0G@00Bx*MUJKL*sAF;y5DX&nyGgsBv?oY=nzY}N_6O45 zB<)?&{y|z1Hg2;~3S@RSBy9`Qwjr%QX+uamAIN&9o~VJSk*JAi1yM86YNBEs4&b89 z8KP~7`V);H8cTFA(J@4`fy}=pL>CcVO>`^KgGA2~tt9#zkomWos8cVeZAi2Q(GEm| ziS{Bo1jziGN>od97SW|d*AXozdX(rnAoFh}(OX0x6BS{|nOrH+rbK;-h60&?`w|^R zG=u0AqVtHZAi9xg`%R>8ih5?z+dlMZ^G?QpC(fL58?=qrmiS7WxW`e$akmxBOv+)X$t<-N5 z{gd2cJPI&wA0V@_6Ogstjoh)M9YQn}$Xe8rb{1)u5?x2`av<~cAt1B+G`X)5y+!m7 zqRv*!Ehp_EAZzh!(q1Kci`-91 z>x`?mY3WV01JO_*i(?#+X+Day8Kj*;w3OVdh;AYJInl3(en+$l$b9*Tw05}4n%(X| z=F3*3RS=CJcWkDLd2N8`X z_fVpVXIiE4-z6V(yb6Wsu0=a+kk9wB;~=(j|FCVGeH z??lDhxPRqD1BgZvjVGE!G>>Qr(NZAuub$`zqT7k?CwhYDd7@W|{sv_E>(I|pFQR@# zLx{!_9Y!>jXfBZXw}faZ(Pc!}5H%3pP4qC)b3o?bDxyz`I&bUT-b6bP4JX={=usdW zSI-jtf#@xwkAZNg!2DPZWb>obc24UGWVGI-ZAsdWr0q)D?xc+*Z5(NbkXB9F@ubZo z?IhC92eQ1>6aAFvVWQsq%AoFTpAdBO0qG?3)iM|PBcE3g14}dJ926FEu_i@smr`$?%KOi^R**)k= z)Cb5kZ%^88L}P)>mqSRK3}h|7M%w8_OUb>0v>Sm;%RNMo5&ed8uLGIpPf6=s;k4dF zI|ErJ_aHie=s2PiiM~#B9+3I+9nyXXWOjc_S|e#qM875X4WbW#Okew5+^da%Oy72- zjUcUxXd=0DiM~PfEutR~{gmhdAhY`%(QD+sPqc>I(*Ew>WXJE57LSTy1r5%v#}v*TadO5Y5hqXLfRETwx3@|^b?}Hh#m(j zRquaG)J(LRsC1Cal@V1CRTAw3)Km2xPBevR4$-MZXAymi=t`oSfy}@AiJm1|N%SsJ zGT2-6ASx%?8OZz_L9`Fip+v_L%^+GpbUM+6K<3{yM9YaDC3=DA&qN;*br|AWx&xVi zTM+F`G>m8zQ5DgVM8^}&2QvT8Cc1*?MxuL&o*;UeXcf`ap+2tW5iKSb(=u?&R)I+A%<8V-~q5lY16v-zK^S$XeV++M}es zK=fyFKLj#Qi$=It-GI!~&53p(+Jk6cqN9jr0GS7;5S>SK1=0V<-rIn?SykENDIg*Q z+bSqv)T@IE8la`+(~Fi*QG-^Bd`+}KDcnLzJN-b=s6}X{daEenXBxjh-WJrF3gFdWA-> z7WXls&jnrLvw0W6>Ckj1V=m?<~2DE!A zUMWusXs>{FES(;ZT?ZG7J73&|;+o>#C~kwecZ>Ubacyy*6nC?@FNwQN+;_wsdSrGz zKSt;Tp_7Hq3CMbXvCw*Y}yU+QpQ0b_Qd#uo&LVF7xAauCUivlu# zuMk=)v_|L(p{s>%5V}R^>j9a+?+e`{^c$f+3+;4tHskR^PZ8QbAoF*m(949*7Fs2A znb13g{z2&D0hzy>g>Do2uF%~=eWBkAZFfu-<#7R-zh?*?By_ycsX`M%7YSW1w8OF4 zzM3Ia5!y#+PC$E<;_-1x9P8Ih`aZAK46ZdLyYs9@-+}p&p#C=fQ$Hd(z z?kfRVUwT5n658&#Y;<>_eT1GX^b(;ngjXpjg^Y=`l zIYLJZ%@4?Oyh7a4fGo!vaaV}DR_N0j{ff|cg?=jZJE0w4nz`Cj=m4RkgkCN*A@mxd zw+LM$^eLgQ3H?y$=KLZ1%EJby*#`$9h#`h(Dpr(`)EFEl1JC!oi|!91Z80P5wjovEmTS9jSWHWv(ZrZ6CH&bZufXvI>fXwNU0hz0p zX!LJ|CWI~$S}XK!q3Z)O2R8}bCUmFJrhqKlgF-ug%$>6 zc^l%I0a=bojlM^t9};(?bhl{qc8&f}+HZ}ki+qQ;P2wID+U0LEr%w`kj?i<3ju$#rXd)o5;sriWR0F9bfM5Xp?3;>Na(XdU7?={{Z?qF zg_(mV3GFX*q|ix1=L)@6XnjDt?u?gI!fr}LK8x-5qgWzHA0^f z`d6VJ3f(7EIww10&Jg+=p*ccF3oQu9*76*oi-pz;y+`On0ohskMxk4TZV$-rbM6xQ zWk8nWj{(^gV&`)+v{yhj`YdsW1Y|j0pwUw_dbYT~6S^cIoAEYr*NFRs&=)oOoq){g z-2s`a|JLZAgm#+9{Ouw1455RBjt|HjoGLUSbdk{I0a>Ziccg6ilXs7eC(LDmPdiM#)q8uu8tk8+lofVKpUM+5|xOWSERHL64`nu2$gfmP|%lk)hJ1@=RJvpFq zIHT`Ynk8vg_dU#l2YE$>Qqb z&K0**+(qJECvLsCw~BkOxU0o|RNN=T?Xf(&p6@NRpU}ZV#|31of11z|p^Jsq3%y6E zEz}YE*MRIk=MJH}gnl9PJE3WRm(7?iw3pDc12TU{2%RAG3ZbP!uNAsN=xU*l1~e0U z^0Pv>3Vl=PKZNcTx?kuoLXTaM`FonsY@s8CUM6&=&?=$Jgx(s^O!#}h(Dgz$3jMRt zSB1VO^b?`q1Z4et)XEI)F7yncgM^M1I#p;w=$?S=^T&Nc1EHN(WuuP|$nF#O3}^-_ z+FRVS#T_K>x#Er!R}*)-xHH6^FYfQeHO0L_+y-%1iu+JN)|bx;b%lN`^jo2wR%bJw zB(%TKkwPa4oh$Tep(}*04rn_1a)Z#9guX5GpF;NsWS+ObFhhF^?JIPc&~X7-js-$z z2rUojv2gHOp$!39j`s$%D@H#e^f`_GtGMq4WI2AO(FZiT!>h7*GliZOkj@3jId9?OvTl-aR1e)icB$B=lm9{;kmY zLa!0JTmg5L9z#o}HjZeu{Z!RZ%;z9IBop`Qk1N9`Yk z9k3SA-e_d@>^koo(f(6@x{7W%c&v^QikW(w^sbU;An z?+Bseg%$|CQfP_LDxo(By*(iFcb(8ip)U*FA#|_MZ-sWcG>dXsK(?>05NZisFLYx- zdz9kw@!5cEkKZcpYvS$@_XBZ171tN{dvSjjx65T&j+p^jj*7Uai`!4!9C615WPLeJ zs3G)vp|=ZNFZ6k#e-pY}=mDWeug!AoCA6Q=ynyVCIbUdz&`P08g{}<9JYOsHX`!zQ zeP8IO0a=dwg-Yu(F8t58c%SoRp=SqVISvoV&fYH)I$fjZihET+mg9{YeTPP`5%&q9 zF9u{Yz9sH%alaOt_QuT1%z*5U>?r}6tNk_lT%qHIP8C`#v|4CwK<3~oq3eZi61puQ z%XX*GCZPudGFOkfJahUup=SskDD?b*EN@L*Js``mM57mK^ipwGN_VwJZ_wz?;=U&I zy?`w8J>nh^+F^a>WoAIO=1&QT-4*v-q2o3Ba&e0TvWhMeS}XK+={^{cMcydx%i``3 z+N9Ax3GMQx%-@rQ_7OT%=-7bF%ZcI^24s1ciED~mFZ520UMqA%Ko;*7akmF#@qQ}q z58@v4=4`YQkoB}GG%i#VstYX>dVN5a_pL%7(CEj7IvV||xbFr;f8y>JSDMU5cMZt= z?IrZAfGqDJ;$9Gt#e0Rg<>J-|U8&J)g>DeKMd%v=S&koy`(;3uqqHG&H6tM7#)Rf* z^k|_4LgxrwD6~%KJwk1vF9`j+(7i%`5_;@gGFML%nk)1Iq0@!V3CQjfR|vgM=uJZJ z4#@5z|2`nQf_+%r$Hje4+%4k1F78|6dg6W}?w8{37xx!&JG?c^J3S!tvb(ruKz6mi zT|?->r1B&^LsBDD+FAKMT#cBAYuV^qhd~F6c0!V}xERbh^-Dp_M|f z6M9QP=I%?so`m#pv2*{k?8<4sBjYc;MmEV>5s|f8YbePZ! z12PA7p@vXXXfhzn))Hz9bpkS1Uk%9m@_nJ73;j-L`*&w~X9Q$3#sab&`)TxWjlM|S zDbk&-(N!9~MBH11-WQNXzFyqtg>DPTdT@uhp9IA2irXwyeor>KXF%q@8jwX97kZ)4 z$&+8d2i=ZKpp?gXLJHF~bl zs(`Gv%f!7aAdB}AaW{+mhR|Iay-%q0zRcAOp}!HDBXo2?mUn^BB8{#TTBFeo;@%$+ z{fYaGxLbw3rO_V={URXC`zLXaZDsME7LfIHuDD}_PSNPOLaT%>6M9ELmg5?6p9si2 z-zx4q;_eapy+$AX{>;l>LeCaDTQ0bcoPVLMH}f{uT?Z7FsKGmC*GJUqE}7;=aEoAlvtCai0`-v$!vb`!{jl5%*(p_lmn;+#kg4aBY@%=YTBl z?&6*#?tKA0G5Fi9v_tssZ^O?q;V1iZZ5Z8cS}FeTR`6$HJ5xt(oOS8Y_%&g?gh-{* zuLC;!Ii=EZr5D5n(w`VJ&Rq~*J_CqVSL@c-Mfd0Bl?73akr5a<02{#JqOhyOv>uHr6Qx^xcc_`m&1 z=-Hrafqtx4&z=juGb}ec{@=fnD6^oB|0BJGJ_L09zk?<8VW69ZoCkvM56ce*T`9;9 z0zWw{H@Z=fTczz`xg{+Z4RYZ58C!fnMN0`K;4t{^BvE(nrE-T)&l{4~OxO zhMy1d^<#XE^R|sWyuQSKZ|NuY`QiSITE9^-yzaV?C;nvXnyqbojk=7_;$&PFBl2;6 zHZRlp*G!weMs4N5SqdA%|C+tOam#==e8ZsTR&&{ z<2b{@q!AEj_3S%%Jyu0 z-F7_Z=dO5+WxdIcw}*P1K2%*6_u;&5JD#^4&wjtez2<+iJ-h9A-gbSS>baQTKcnze z^D=(a9M5ICsb0Ny6yA1y&X4JB$8&zZ-`aI`Yvb8od#Jih|8QR8_1XVS^~@*Zhxhu{ za!qwiW&9(3{&2lnAEtWUT0Nu2{q-=zThncOHkN-zpQ=}pkLRQ8HN)}!!#$>k*JW$- zw>F-6eyF-k|8QRYalP$6JU=gIJ)G(o&iG2{aWmpKN3%cqH#19@JT82<^6;61@Xfv_ zl(q}sw%rBa(~RHkT!eS=+m~bE8=L3jUHsl<{2u12@NN2CW>&+j_zvH{j6^LbW{2;& z?lQCEh`E>(zg)>VMvUi@Sy0q-;t&wcoHz_o`#CZDKu9V%b1)>6IWhYnNE$hF5G3uK zm^~Yka?TtGNjE2E&w-?sGlxRb%Zb^uLI+ZMQuE8qu0k4VQ zmmLeQZ`rX_dU|;MbokQj-r;q@GfJgrh1dJ%mP*eKuU8&ZD(xR$=bTh3%?_^zon0!0 zp*8PZSt=b8ULSvHsr20N`n~Yma?cB|@w>c7h1a-p@w>H;E?q>lOQ}h;bLms!ZW4E! zxURUqxckI~FXkfhE~Ooab}ro-zFi!%?NYjpXy?+rMaz~h-+#&3pFMMjX`45fO52y_ zowNANRr}AH^|ooHHOB0J_KL-eR$aI_OpRen+fO?n!sO5XXD>c$^|^a5h-Cay^Y+sY z4LytX<$tINJ&JjvCf1t%*?-mIi&pKu^n%Fl5Pr6w7T4z5olB)Z9P$0|n-wv?&-Ey1 zj;Y$(g*RbV(=-~Noj6V_~qc~K@QWtv8TxuU?tm9anBtW6oAIF)D>e=^Pd0<*fn zw8-pG%4Yp@LGyhvCDt`4Fi*xe%PqgbBMZ!;0<*Tj{A0p=F1%Yf)i=*CICD{B;YG_< z9Jm$9nHQYBHObb4ELyfa{BM)D>}BP|>T}N8ie|;ii6!T(nsea7#*$U58jBZSaQ2cj zFL+3E4xamP<}{G!;mujK?A&u3i??DXG<@NTMa#C}S-%l5Z{fm~ix;h4v1HZ73l~i+ zUUdG#Ma!0*zhv>exm(F`;!96DYAccxW^F}q?5XpQ+M4F51zT6l-b$XM7KCl#3q^^g z1Ln@2Gj}ZiGy9-fbLJd2>)=D@`@qPYv2$(Oqe?&c#rsbC z@Y}X4J(I_@KPN^io)LQ-)632?l5=+E6q5{pBtkto*ADT zzQgbTK&IryKf|9Rqi&B=!ad2{?Mh#IvmMay3f#OI zGmZ)c9&pUD#~u0d+DWw+9(DNB!+(xG;iRXhl4eCF0LWw95tz35YlGRJ=%g#E_ zy*p*e1#=FppSZZO_{^1y>le!GU`oO0y+IR`$R87It&a~_VP1t*4^jEC%h!HJ=Q{es?pDJK@Z z#d_nx_ps!%AD;ZcaCf!S%)>(S7cN{HepxB}a?wsRR|i)sRxWw<;)Sd5{%PU;s}@b1 zxgxyZEsRI+;dh%Bu3mD%sxT+8(*yfAK^2*BI<;wIB%&aOT@~IhUa{hWW#N6y8q+XK zIlSG^Ooab~e2f+cW3+G)i1SJhgrDofPduPzOuOz~=bZSd9e(-4o3DN5=J&qi@^CZq za`5}Tef;L1y!fWyJn=7&x$gIOuHV<@%$T;*Q||ojy0<^)$@~BNy+3)+v~zzHW5k~y z{o=}hxxO{M^1SbUsq}5|Z(qCM z!O!hEdBvd)shR& zUiPY$W9KhfwX!~YR(;6@iyEuXUL4^5v-Y1o>%h6;wZ3}MidFSR;kV1e>%ygrmo8d< z@xqn+PyF>_zAF4STR3hl2Bq-U69gV*&-arJm>GUBwdC|duYTqIKg&Yl|< zVE+RTikd8M_%s(bZ0Ob0xgPq8EibvLk>Q4Y(IqlYsL!U=UDhd4*dTne8@PL z84u1fhQl{rd*hwMj-}enkB4*PZ2>k zogUB_xK|SGT)I4F>W4Z73VfBD&Gm45y5H}@~;4}z6z zLbB4FFRwp#@aAK8Tkz&r>~!**SMPDk{0(a-!h??W8ykP#ym|hnsF^+k)P}Y3K|~mD zhw=H-XW}gcMomPm&7fw(+W6FEh>DLYhNxPRsuroPVqJRcJY{H!HR`-+S@4+qyzR1g zG3|NVXYXRh^LEJI#boC_Dtj06oVR24F2+Ca(e@5`8$nzsH6dc+gowElBBoD>=pZ4Y ziG+wg904m)6xO32CTDgd&Rc-y6a_902RE$seN2NO{D!qiwkfXhhPBauk{EWJ+)P!?(WJG86h&SZ~FlIpkyR+SYPob3C+-1}WmoPJWb*SZ_3`7&@O*9&K)7 zM8hFvO)*s#L{36u{Gv2Qht8(){8ltKDtCW)v4$a zXQ_z2%&tg2ht9vT;4FG0dP-Fo_E$9QD+poS27)wX#*}GjOiY z&@h$HfY2M(cAPbY_Gca%*s!+gR7ka9EyQdF;(E8RR=1>nE`^<9IEWdJ86ZwG_*ksm zt45T`j1~13*6`LF=7OYUwQODTx!T~Ksup|8@P1Lc7HeESHmn8Sur^o08d-#3@xbZ2 zpb=>SXlhyjRe1)kcN&Wmy{bR#7S?K3skhcPAwtk?%P8a~HT6>YSZt(^)h)&vHxq+6 zg7AJpdtz0oFAJX1;t_{yLAMB!QV5c^yKX)@E+b>*lwZ)M6GD+5RlPWzQcUVw#H60$ z#DNPBoStF|6Mffwi#p~5QP~ecPSSdd?aP$SGK3KXO)=cZ{UPdx{y*JgR{CJcJbD zrk8gX;1`rs9v;@}wg}bu!f>Q~(w4OdA*gB>yH>MUUezzEnnn%c3uASLsYm*PveKTb zft6x}WldUHo~l@jAf{@>M8r++qdBqZGBP}xhgj$u6zS<2ij-;%cU+fujHK)0sisYA zJ0HO52fe|t$}gx7hrPm&H%wZ$7WoXM`Yvh1R6bUBIH~TK{R(g*#Cg|{Ej_BLMISJb zp6aOb8Op^qrV1l0ld9au#Fcoy)v(zpnf{Kk#epDPCnwbgPN~_H-Y}2Ye%+~OYV;l{ z$fKG5+DV>ecNG89TaULcKrnRa=3=1^)(XemVWeO-UHE~mA6!!fi|LuIV#UHMRWRlc zmrHLAEo)l1YSdE*oSxQU)Av*dLQmy##Zy(yd<>k5{m%QU(>zSW1P%oH@N-+{w&TLF z?M+8#i{I-VjgbQE;Rs%BxK|24&AFBTkezn6d)pz$qh6l((4jPAK!@b;eA@x0`qm zh<#fkPLy|f{8O!TU83-75|f3gR>wGl#u*c2)cf2F_-J?Der{AQpEyOa}IdA~TZ?I^_cR}EO} zSXs5`o8efN&%n7p!@wr`44jDLfU)Y<4<8o0q-Mq$g$oo-anc=$Aij8Yt>G$1ko3-@KkOFP+Q#~%h?5>d4Cf1| znOk1~t$B(`J;jVw=aw0B3f4Hc?1aGnEW_=SQizkbh}IA?-F}{GSWTV+_OZORZfqXI zp~SRnH4Eoeo#92`g=XYo;C&!Sx)T^HSNXk$L0aQnPqoYkHYQcvq+W&4{!+;Mpmbvm zEEbxV_7+({`Mm}^6w*i8tufttijDMC!+MJm#^OXzF+9XnVc54D*2=|jRin@Y&TU(z zp5g)TDfR;+=|oR4Jj7HLCi=bRg{+|y?WAS-3=J!w5?`nyixje@7b;rwJ~+`+3=eTyc~1TB7L=9x1!b8SVbZqMCS zlj^z3>!!+M!CJ>^@N=O^pL}vI#AyK-Ayp~*=vjD-q^fb(+kvSdh6>gg4uhOaVMk^0 zDMQ^dqiRUWv&-#aJ(By=KJ^Ifw*rjBtl86wnrw4Q)4W%Q`JVCJ;nb|EC0^HB6v0B_ z*zW}x>03;=r?705cU(AFOh5F%UGgb6`&($(WGr|}uS;~>P<6Ug{fl zW!;oz=Re{^InNB78l-9QwP9uaHN9ZKYY~&TLuWDLvJ3VjdpW%2uh*z`618 z%)&KH{i917NYAfGl|I=*T<;dv>Xx+Wil?ySD29WWy(I-PDNgjUSh-h? zD3cQ_Y6h&~tv9TXRp>#w#`#>H%F@-V7JJL^eo?x`H6FK#xeC_E`lJk3R}FePH*k$a zQ`2=pyZpsgS0x{d6LTNj|Nc%1)@o+hTWecc2$6OTxk*jER6Z6P>0_~LKGwLI7^rf; zpgpmw)R%=gBR4pr(k+7c;@QD;ztqh~$7LK0H^VO|ax()arAJlI=6V&Jr+bY_D{d!n z;-Kims|pi+*L;gQ<^xgb7ID&z#c*B)obEMJ9cQg+;XO4z+(=mC%43i|xId7a6vOpg z282%CGL}~{7Dm!V@f5>D3>B=6n2XTqMXq6G`2xyD`2s3NArXB{7F$FggJPLE<@Z|7 z>aN!N=vW3%HI4GtFuc`+rD6s2oHZ7ZQ?SN<x8PgSf%5T`BjD#Z17V!A{(T}FmS^AHPNgCad$Ly=Og;g0L_j*)a-Jk_*`ZRZ2n ze?Vg@|KZ0ks1Jv|lHTld`}qu{`Yvh18tG$oi`FolhUY|x^R6LVdN@`s14h!N!U!p< zYEew8TwG(SFp{crAAI!Cu-PaXQhXweF0!W;lWGH})ND#`m`7~C?$pDEzsQqkw<@ZI zeBT<|QT%OR_u!uL&E;n`-&dXH^OoX3sM>-J)KGo4%X_RF(WX;z;<#4Gwyb*+5jTo^ z8@Gnu7QgOs-b-jP+q7kA5fogO4jrd$HxyvvlcpzJsU5hu#~Oj(7p z>68(B<+iVTgjL5bWz(@&Mqa1eu8qBj{S7jfHZDV8acD3c7C+6vxqTOIU=w`?PQ-D* zSamxle0VrdpC}=&zwE&pg)Ns9+0sf8I(6Hyq<$h*-C`_=>6YOkCdG+)ELdalUO1vs z&aJxR12}a{3O!)bruEiOoGen6;oia;!=V(0>)70y^8xJdjC3XONg1o*CZZ8(0bL94 z3!o}D0c#ZcaHMh}&u1fdq_;L{Nijd|8gi2w6f5UC<*{Imz4YNaHrI!%S;xz+ABdCg zNCZiHiy(f3vx8}w{b9GT);88BZI}=57Q^XLRWp?@fYv<4q@H5Nsw{2sVYqLd(8`3 zLnqov%kmi-RzM}bP({keYFbSQN!4U=LC1&t18cpauw_))CG8d|WJ}NUwB~(qqNf-h z;8~NcU52q`>Z&AZq}wDf;MHc#Nc~ao5{{sUU_5)))?hoJ(OxW$`IP-7=$UNXfIy?O{EV`_n%42<*24 zjKr)EB=_8$(lqZ?l|#N~e0MlCt7?hYwH8INP&oE`0Y>^36YeQ2Tjd=Wu4dH0QE-?3 z#R-h1A4K6Py)MyhL)GcQI2^(RtWBCVIHWbs&4qfj4AWG>d3s9)=jpu%WBG|q%h+{g z_Ka$Y^82VZRD*jM5zXsue6E2GXQzygAGHtR693=&x<~lOwBql%gnIpz-0*~d>M_HV zdqe3LIAW)a{a-g0#Ov3Ng^_Ul^y3ScK4K>hU-z)EmB9Oh&~T!hXUaXG^eY>2qMUEa z-Jq7K{1 zw}IVEVcAsz?1g$H=v6h#;Hj!n-af63P+>mXff;@=VU6JsA{7o?rOeQC6emtPsvmKB zF6tVEW0T?GDSZ;iiFtTfD_f;L1Lxw*!f*{!`3!KLJ~BjT|74H`((@})rRP_~^=@IU zZb_T2cnUj?VmOHDmK4OKIMK&q*jt82 z9gNkriLjH_l&fG3igbT4TwOJ6`?`nwMK`~oe)T%m@w~n2ns4NwxGo5i-X3ZQ2%K)A!bIOS-=dE715xP%+0p}^ z;k*ji-`MHd8A38v)53dd-1?JKu+}vp2051p8gi%MdaiiHN!>D*S1}ew7>g4<)ie_j zLj`Li<|1@@k!x64zJRh(zJQ8RNJJl##TL=Wpjc*3!5XrS+^610$1-?|8S2pveK3}% zkS#qjDpo+xSz`e?1#9d_&hkbmy&>aVi0OkF&^%IXq*ozsdT+%7{DP9oC&F6YYN)#6 zNg)xFwu)VA8wD{{HH(Err20iw)2Kmwp{g@XJ<=DHmG)c>tP~?GYtqW{RK;2ZaoQrU zLR^0*rb~3wWn_3X53$fSDAL0Kij-;%cbt!H({F8XBE)ptw25u!12~;H7*_cO_2IBr z(hrK*QT{2iKArlmHLQ_7R(Ck5?wEaVIT7N#Ypel-th8zwFhZ(t88DKnYEew8TwG(u z!bqyheee-O!)BukkZ$|BNAg#!Jc9hfcWha(I(f^QQ!ZBCTRo|6Yl`A_Z{(se?)S%DN9iH!hf?p6LF%v!IT61?##d`BTkgJnDRj= z^Wt^JOvJaF_yLG3vF=UwEFv*xx4oTpEe`WCAp6|7O% zay1}Z>I0!uw}_M82~gE7#)6oQWO#^4abj)))>yn3)}#5fk(^sqSvuvGixhgmq)qFG zpEy~h;<1)wgf&b`?^`-Hx8{-prz%pIPanYPrvo%1Z8w^lE(%rXCt|@Gg$?I}R4&v$ zg&q1Bv9TttCd^N}hTNnE#mc!(d6}@rUixqyo9n~DQ(8RYq{Smh+FJxk8(AJ+JqGbx z2-e!>1A3O#u({qX!+EM^DqjGtd8%J5vu#w>trIim6s&P>*$IJ1ehkm&>M%ee*3`A6 z2uTVv(%v?#Ca(ha?e^9XmEpJuo~l_mPj$=(MmUk11G&>!$W01CQn!qitNdQWU^>@R zE%SlgsSmG0==9En8{8K#uvor;s#T6G2=DhAN?}s^D7!UgrJkx;I8QZ$E&}`ERqO{wn6zyz@)W~EOjTi`-)mmT8agp*T9(hyumURa zg(^}$R@1B@Bvq5e1sxym53Kcy!j@5Gm$X}?kS#sc(VF+ciJoG3h||h*>VLPOth66Z zGXu-S2&uN!8~NcU5625l`Yf?wE%M<>^<2B_rpjZ%TE}YebD>Bxa4y7Y0T>}wDf;MHc#Nc~ zao5{{sUU_5)))?hoJ(OxW%0pB-7=$UNXfIy?O{EV`!f#p2<*24jKr)EBsXrH(lqZ? zl|#N~e0MlCt7?hYa|9H@LgCo&1sLgDOt`18Y?XIhxSCM|N5NhCc?`zV=l$@MUYF>$ zq3ZPM01jaS)+Wsw9MT%+=0ff%-(UT9F-&tJoTs-Vj8%3%nwGKa%Iq11I&y2A>oe3t z9QQCHns;x<)6q^kI`D7*Z++b({0}3;*F84j!@OVeh$sBBj2Wi92TH%d5j$nv8tcY_ zc>UVDf_CWBXg?K)uX|Y79>V&yj@X6Wux_3y4~4Q8Mzf1b#EEjgDZc|{)hQ!(N?1Ju zR&O_}-C!>Z8?h6If8E2vb`dt;aP|S#E4TgY9%0qvF_X12ZjnIs9ED}^XFHyn({mBl zBfT!g)gB7p9}bVxQ`v-*E-B~Y?6Aomgf&bRkN?aqoTq;u~@lRjVO~7E20@<^vBu5BAdVosU(lXdRqD%vr;!^RQRx;z(!&u!(stL)N5^Fx znA@E43)*x-DAJ>@#aI|&EKc-P(@a1N6|9Yzi_qzf zUBk-q1(c2Q1yqbeBKnvtwun9k#WHis@3oxOU9I=gu?(JS8s)8Fc&i6X#R}*-Yb+qA zV2%CAS>7%CM=RVuDa8zE9$UmlA|xrqO>e+ifL~Bj`9xT&TMgCt!f>RJh*YcCwRW*< zHH(EroY*g_nnn%c3ss$A>XE*nthDE9V5JygS(8?lrz+MWh|?B%72^6&vbsb!T}FmS z^AHPNgCad$Ly=Og;g0L_j*)a-Jk_*`ZRZ0x{Y##~u*xr}4~M9JR}3>Zn53L~VbszouWa&e8R!bqyheee-O!)BvoNcDH< z+0%+iwSiM=Hl;VrBeq|6>S4oQoW{&qR+sIRTrxsaT*@Zw|(71?MA!OyR7E$QfZBSZ*koD z-ujceUzZVUT(foYDpEcJaC$q^GHYeG#$BWO@rB!usysZbQP?QX&4v8f=*!Y$8gFgV zk|HFNvTMjqYGA6G%g7y>$AUHX(ueEVTptc`(jxj?w2@_70feO6{;*qE zYa0tag$!sbxI*l+9Fy*NR~;J zry5qdr+|GdZ><|kVK^>=r)tGUa@jG$iQF8>oyPJ$5I5ZkjFqeWUc(^6ajvIYwg||b z`tT}*PA|dS;J$!?#qtGIt#V{Rc)!K} zty~OOH3~i8+_qKfDfYut><32DiJoG3h^Z<}^n1+PWN z%%^IyxS-?1{eiV!QP?u7?2>ki6tbnKI$HBSIMGuK4>8?h_^-F1tkf?k%ftwiwyh>l zRjox3Q&pJg7t{+mw-uwN8PEe#7*4y!7L{GQo5gld8if(Y;>4VSHD-XG!Vzv;d5ds#pdet7qXclB&j|nAE^j z5QBm>hQnYg>_j~%K4qv|W>oEYcDX&QM{0g|{So*vlp3>_Q-8NL+h-YlD zHfh%2kk&Z2?R>zw@2~#438py_&eMAj#wt4>P0NTnII(9G>Hy{UkUwd`XhU2Fn z1leI9u@i@{dsx^O!uqw2I8n|s<-4J*h0!c##EEjgDc=EQ)hQ!(N?1JuR!9h1wCPCmt+|KihGiq~{{6M|xd~t34FHKO7$C zfU*fEoe$2%nPtFQzkr%S~(&cpF+o~|Ba`9W#bO6xeSL zSR;!NTs`3QFJ7A#&KJ-b-XFXy`V6`%)twJc^ltmZZeeZ2#%h}oA?UVcR5QMi;wD9D z>5lYeR&6W$SnQgQg&_XG^9$N@Nf9S49&yq}4$Q5$h9K#JqBlON?iP@RH8ECB`2}qj zt$C_vK0L*wzD0Fwk*7Fu;KBo^`?fIAcMXYHL&tm|Dk)@3j|_(MD&Vx;q&m)8)53dd ze0bSmjVq5q`r!URZc+@_a~Tjib<0>@#aI|gEB6$`LktzHjhKtj>5W~(%JK!2jq(Ll zj6x#%m@Kx4J_f}ybIR|voYg+{K021cQ%$41H4Ja{V5wLEJ!g#t z+b5-%0nKBJ*hqvVg}CVrI1BI#N-CcSYjvxk8ebTW6cUkY6}#3hcCBWykcboeMOD+N zL42XAGfX|w7nGIuTn(%gBP?su%JNjjS_E<0BCkT+^tPH4n=T{6qj`vhu0fHWuAxY& z)^Nx9*fxD4&501xZPO;Uoe$u2;$T?i7u1KtUP=Fop>8em8A$bA(uS#gtnP49dP>7{ zBE)&ukS#s-szo0#ke=$OszotdRJMr_lcEYEsVeuuM+^;{jgsl_7+aj|X~m@4z$rDG z(i`Rx+pjzIu;DNA6?4$6FU52>0qurPfIob+A@A_J1+JYgD>216x11 z=0t7}7$#M*V&Rok$0ouiD1Cqr)~ZoYA#i$Hht2fT-L`N&R}&|q4#ujP511we=f1Bx z&BHXUJ%ayrkN9t(qOn=SVoTjalh_9Lmc1LXRYTuL^vZXXz4GlVTSu|x>?q9m9jVWd zo#N^=b86ih`y_ukKFNE7Bfsup;>#fRz9XLSk4UaIQUIb-cyv~@3_;wSog1F+gcEpMDE>kXt(swK3M0uYncYw0#tVZmW+rI7*_BD3t zCVRAiy)yDT-F9v4MeI*RSlYM@fvveU#NwwJIJfV@4Q!&%z=>5Cs~&M0p2t_$#X?+v z*@HC-TTX~aPTi8~yE2>B zTR(BKNL7Y=3u_FAQdmRB=GL4K;Pg^R3iCM;*sqIjWy&sA*TVY(&@LYy)+lTg=X$rj zqT3N0YtmE*Nw@48a+4YqV{x7GGGUFq^x---*N3ZF$9?gLlkP|a@x`la4OcmWq(?@7 z*e$HJjrB)C^79?&BA$AXLu2K-5+@vcpnIo?gYllRerBwkk&ZYQ!Vp> zjY$v zsz~`*O{)nZshTV<==gAdV69gawu~yfq}?KgZ0UuH*1Qi+^c2HGoK~Jw|GNccrG7zK zCPtXFZ8dqSYAu48s=`FSpkBzitr#`UfF6*-aN0GtsO;L^EVg^nD2y-`C*~BaF$44z zj+l#VBR~A);dt#yKPWb=MLs;Ko~yiWsyr5~b*u(I7m73k=R%wofDuxaqK}@1$4IIg zcfB2$3Sy{Wjo~oJxfFKtveuOz75_4MB76V|x2*L%=(-tUApBbeXXB%Zt8d+y4V-}i zXJg$g8>nNz=a^>$r((eQSvTJXPQpM_uA=>QXN0l!Yv+fdV63OH@HfRasfI}?lGQ=v z&!L9To0e@}b_9#dIT25|kC|(^@;+{)vLNUzHO`d%h3uAcqq?GCRBlL}zbrRr`=?5< zgEc6I&Zl*3f55hjJ1RG%PLl^=(MU!?J#H7DSl!8|@j%UUBdedJvfL)aGUP#+8~K=f zihiEAoh>$;REGUoDmcjY1Vcm0(2>gG$edr4!RUVGb9%!9HD*+9sJE0G`6wv#(;Vix zJHxpPMaxWBJE*sm+b>FCy@zv;KlFw}io~*$*Dzwerzq>Z9kPYQ3UawzK@$(<;ARjx z8EVWFW#zehTkScGC1*0*e}0_13iJL(dJV>rGw&b8m66)t!9W;GyS+bW6GG zaqmFz=GV@+^wwE#UR_?hd3E`czpM!>IQDZSTJU9SMRiT^YqKU{K+sd0~f97 zpWd)4c$xm`wX5UH%WbRL#KubSluh+-A!&edczT zelgDLgyG9KM9~+29w*JXd_#;7Mq(L(yL^M?IchAtx%4Y*!blTyqKiwvw|Rb;G|N7p zUHXeS+6#On=LH;hYJl@E{jWGO5k}Tub$0mg^qJTZY*ITg6MpkXB5cfld~upUmDM_a zBuqbIb7Hlq>K0?QL}9(--26NobLU5COnct;nU`98r(GG7o%g70Eao|H$Lw89ao(e| zca5NQbt8HaS(tHKsLoC zG)*3a0_3A0`cHDFbKoSFG(s~fH>6w2jeHdJhwDyrbAuUa%cjPR%3Y2&x0DI>y3QOUE5mj?r`16 z>K8$|A!Xc{DoZRUp)tru%@i%orj1zdsp~GsI!5G{xqL-nr?IuV`@?llog30Ewj}_>(s}^_KlgMrYtd>bRT-%kovlZbNj}$N5{=_^BLvH#!UFj&xk#Y zy*8X1`Dkvc#nznK=-uEFYn6uf@W|ZAhuoVtHt_i{XY3O1B5&S!JS5(5#EIk>Ncypd zhzmRMZK9e7Rau7u2K{w;^Tu&VP%i@65t&4p3rST`Y-tk7EJ(Vko%l9URiVOWX0E9& zbv{`;MosT88n!%M6>ATw+=A|G%QB88;cY79;gt*ZIL1>|OX}^@+6YxmNp-e{L)Oh$ zm=6lp=wqNZ>b9xpD9)X96hfy@p1anMapwb`{HJs_HNE*STbX%ySmWG^3)e8A&j9D? zhc`I)M==egUl2jI)Cc0GZtIq@smfuE!j4#dZ4P>NoEab{#ff=1U0}RwM46meam@hs zZefiqdcdSDTNgjKU8JhT-ZECcF5JWE6TNYp=vAchjNV$^)qqC$8uayOUjS7;L&pm6 zu}FDU-&C-}W)yZ6thG&u5NX$tn^d{jA}&>4sV*WuR@cJ&Sn!lqjv#(V!W!bF&vFrG z5 zw-8fRm*ZCa%e zlVUhe!9W_TVg>Y^H5TA0HY2BCjs3u2TD+&20b;5~OhjmZyF{Dm-2-d#;ZdJoI^Q*) zv}G+q2>NIjyH+bMd%vh^8a0S7jMXVpbepTZHSdFSJ=H8GWw?5D$fOAUKUq+g*;4_q z#!4~B4BQN!s#uF4rfS4QgidcIIT59$;XCr7-y9lPmgefR>ZxWN zPM;IBjq<8NQN5!R|j zA28sL7hSl00p;QvGZscz6IHnneq*^|vr#gn&5 z2v2^c{F1^Ug|L}ky4&Uh4yj_LsDo6^iic@ZaGst~%BF(pG*&(l)>@Xdqh9JmPt#HK zfwnMQBV=%2Y>wvL+vw80jSlq|s}&83v9{`M{7!X0X3tKUF}+6h!PU1jrVpow$@l_; zC@#7PY)`BX)`6plo7jr-suymuDyME*bqzM{>|8}|;{ ztis4R)#i<32;`kdoJcB=45C$(Y)4!oxf2p!S;S5PJC(p~-nfUe6B(!4ym2=K>bP7H zCz2VEG@T@3C(!{Dqi2?}Vt$F>s2&yR2lieJoc5opflCRTs-lZ9(W}NSyr&Kp}JIs-A0PV_lpzTjzV02PEjMVzYz=8SeDPgxjw_d`r$Kh zBK9+_)vZN&27UPNI%|mQuV7NOq=GeMOYbZYIz7iWENMPh51M>Z#)6n`NqM&n?_;s@ zT;=y#&MIj&+F=IZ)GevLD%E|EpEzml_7pcqtr#A4lDM)Vk6Sx z5hvY|h?Djfoo{wqe1?XpD)EIGNcp5qbBp;@O&SF;sd0_^*b@>JDY1Tj@3CL(U(R+4jDF>0Ct%_D{3v}+hnsb;a=lSW~Lu{hCF z3=c6>SkMu3v6B9Cj81hv9M{;ls9`P2Gw9UcbCuUkY+3)WB2_rz(tqf;9>|DvM7S;KH9P$g}w!Zb*jqNaJbHG!KFXB(Ovop z2gdvnv!$yS95N|vrkCzXvj&G$vCOv0$NIs%@9&6@GrICs)lyz7(}}VBq4B7LN!jz3 zl4>G);tJ3c1^n)N^e@JCzIz+n>)sC1x6Slz&%edfj@St|o$d1-jp;)rd9Qfz`3NUoUboEGKJ|{9(-4%c?_;$lu$E@{SSrmF7RQYhEysB@p z#$D188>?+9%%|IyQB9eEwW*g1)p2gs7SxC94u{i)V4w_I(4M0ZB<*d}V&#>?8senK z9^#}FdgD9Jqa;0k7^~xapo8gs28L6L8Jn62YfS1}1oJGIUE|z==F(=W8Zi-Z(-w8C zMF^R0znp?KhRa!9RAD-`hNz^PmcdiwQ!YD3IFXwJiPKoQ30Onu^ibw5%7r>;F~V@1 z=&7c;MefvxS0QeCg=<(%c>%CiHrCfrF$#&8VY1jF`WVEK)UBtGZR94+edw+!r(lg4 z>d_7}Fr255Ej=%eT!i+w20BytrD9Ea1|7#$ zS2;>fW3_BiFdrsht!*syv{tiz2 zf_fFHyhYlPd3ac>Tk+@=tu>7D;kw177*0PEaU#Twg>3$TfzFW_p{j4;t1&SsSi{>i zL%HadDvU53Rk;s7Drnejlng0(nw(VQ$=6KZ6ORvcF)Re(-g=-RPGM@a-=|==DyoqB zehlC*_vEXVx~ceDKNP_xg=Zr$oqnc;-?VS=nSSVj#q?|hcj+UOj`@R4b{C$~>k{48 zRUOt3PSZPqwuOU3hT~k+L8@lO!!)U`O@wJuWmCa)8p}^?*~CtKfeO}8PkOUNA3j4P zWN=RuqIvf=x^!=&L%l_kXi$u`)xC`t+}oJmy^X2EzQ{YObHQXR~E68z)mc4^TxR@P-L8H^Tt^S)NzuC6G;`4rjtbMB)SiZ(X%@qte9US zII2fQdNo3?%Z0=>ln$!73q zYH3l>wYDunUo20-={Xj0(sOLhma6L}GL}zD3S#=;#M}qBfIs*9y*6TQ)$LQ@)GaAr zQ`5@y6DNxl_gbwO9(AAqSnJqaF9c36X{4&fa1BSH5orNk3-1e{D)*r?W*!UHIM)k% zMYlZAytPSFVSal2AUCN&F;+bmlU`cc$UK(snh#gAxn&6jin(LtZ@-?RwoZnb&6Yt`vbXYjj@o36oRBXfw8=bu`rTb zej_%Ps@5r7C1gH#p0L zm`NEPVp5Fdsq%15SkS7meJwM0LAnU+hgS`(QjDaM8qxJN^)*1MolxId89C$b`8TR)hxDq(kP5D7AJa&;UR_!3p!#hRx47FaiR}j53%$_VcXX)vSkdvKN9-p z4Bkr5Z$vNYtu%(yyL_t3&Ny(Yf+K%6 zg0Y%q@N=t1{&>6RIM0gQ#xQq{nfiQ%cPx06nY(CHm<*Sdyt0W-jpzaP_0 za?iy=F(WUKILgx%$it&+FrPjgLg@5?9aT-26vg;T^%q?bGif}hgk|>=VIa-OSP)|( ztdY$PD}xWm;=QV2Nj(Lew!2~~@0L{0mD#dI!ANecJ~sx;D|PfYa3@ zh52c$dNfT6UGSR&UF%o|Ujv2S2UR{CDX;1m-Ev2IYi(0uKCQKkYQ`5(ur~El`EXTR z7ay)W98No7pbWaS_8f&EX>XerE3e!i2IH>1h?Cy#p*OzcdftjeEPh}aJcYRFVSwS3 z>eRsL_B#AD9 zu;(gauLh2aR)WeG7wrV95=U4syV7wJqphH7iVD9O5^(A)x}3@Yyr zhIUIc8t^sHd3tzLh26Hvo)fWnY%Nms(RMZUEIf7_RUM;hY9y?&ET4gMeTIR}^%*$P zXQ*3?@(ensbe%QCO`p~wyFX9D8nUIQN`y}D_!^e9><1}`NpYf&#maM) z-)lLmzuc{=y*dMyi&WpaZCY>r#K|JXHTD@XgQqbR0Baqa>xIBxxFxp@=N64f+ugPB zz5uG)afFSeDvt$gWWBIgbUR{WO_~bxnW1SEa+4YqV{u1TT}^Cc9?N&lhhx{uZZ6`a zI}&ly-Xh4z4UUj>+b_Cp8>l6Fn#Da3hXE+{MY3(86{ z!hW=^CQntZMG#XpVj|-D+c3Y^S}|&x0nH<$VZ{&jdaHM>T8rGsb1J4@1ANrW=V|A>6d?Kttk$xtsTL$P^DGR^|sY=mD&oW>n zRgFh6se!2=PE{BI1#1*`q8==t7Qlr+SCXg6_OKqw{TYXP1orDro_W!Gy4m*ii);<_ zX{oO^>qAi9d8{A%UUqBGmglY2m9Oel728^VV$(KF*Cp*4)p8Uk`tbD-OHUNGef=U^ z#?2cy;ZuCWwLRjA`~k-1jrTy3uc}?V6UkkW_`MKuBI!YrFDCXze4D5ag{tQ4M4U*z z14-3MB2FZ?L*jQy#EGN}Nxo}fC%$zm-G=*Q?YPnWX+$SpuZral-S{`6V}G6@PCpC4 zkypW3tvDCi(oYDqRvv0iNQ(KJ>>&g*z#%Ed!u(Vz33{q^eVl z1u@*h8Z$u88aUU7D-V~Yy*6TE#VtE<>XuZ`S!>y%Uze^;^eW)= z_J&lY7_06mbio$@YaPqrYoO5kpvs3MjJx(CPI|kCIB8OJFm*dHw;ksLanmQM7)~i> zY-*xE419~2)Ki>0&|KOa`ElA$1WvbK#|l75E+|zw1#5L%s+{HdAPtA%v_(zJ&~a|Z zr(AZ7&<8gM5|d&qWXbm$LZ_!E?xI|%gBBwU$BCY5np@;feRvh(j(k{@7l5wuFz_{0 ztav11hRI@!=wslz)-jc*kZt59&3)*|$SGK3hPpcp7|v73mL3_E;!a=zJ?FMjRIwQt zNh{AOSYrn0DI75u+5D}6&J=#BSW})sp8~6{a+I9LYFWE6A0}X}Z7lS(R8)hNdW+_z8PGgZ7*4x};go6( zx7#l$1{scXJ=L_iSbeI1(;Ln~QN;!Iu}I}D(vHl-!&=>n_g!lk<->K0Nim$><#Hm# zX#p4^RkiTB4{c?PKm}_Q)}o$s%SE?TVI)=MKKOK@VY5*(q~u}6Ut`GEOy7&e)7D?@ z>laou5+ye$OwFpAO0D%n5xJYm;>y5px-tV(W-v4hyXjTYS7nBKjOsl&d=JF4DIrjdZTJ-Lokcv6KfOTl(dOojw+3x?>_*0^HgCKIfqDvURV0!Q zBm*ajIFZ~0iLWeTCxM+x;5Kjkl(Q2Vr`o*n1_bIT7Y6-p=H`uUNScz^4sua+9~7he z!jmO}qk2@NchkKX*k{y1AFIy70jDZBN-sp?7T!;Ur*zX}Gx>>X*3fQYhMx1ma0s!< z9&=EI-A0NT`o)QDM5aRkr z-g-XLQUS1rZ0Vf^LZ^3p4NIEOWr=B0#)6oQB!!Tq7~aQX<+;l5wVYMbsw*BibxR68 zNY~g;oV0d(ikqWW439bx3)VWr%PecTP?XOAoURKRkrvRk@O>?n{_fa^r>Y^hutwGk zdquY+HrAx6FhA`Y9FiIoV{u3NGTF#HmhYMmSF?>(Rt-9N_g(Rb!)pnBAV}Is1Yy^y zLXebdTLF1SSZkOMB;s6#^Hj}Lz5ooT_qu({;8ks-s;*3C^b{wSrGhoQP0unT<|0no zB3eUK)oyyVuP7`mYv3DQP zRa9U9|1U*K=uM=Ek)jBQ^bXQd1VKPV1gW8hA{|9U5es0!j-c2P!A7yhidYdViW0Gl z1q(J5k^DdB>^bku4In%|K5PB{YbEQ!dELFw?6c?0+_{r{c|!8Hh0zI(my1I2B}%s? z%ASG$WhOIrk4&4vXOc&?a)YDL z9vkHcCy(+OAM&k512Z_R=%)g{i}*)%6pxx*m2cdHvc)-Q@oD zi|q3kE%OeRnUCM>mG|c_TKA%{a~~~v_R>bT<>bea%64hRcbsJx&BoZInHE|a3q?D| z%MVa3exi{3*Du0p%vyJ^|1Lf~c5<9YW&Z#pYu#ObNcLH^2au#8xA`IQYr#2b$WlKf z`(*lS!@W!zb(0^}E!K{6(va)?kUFs;&PhYA_Cw-ViF4ABg?>o(RpZ-nFJq(l=}~;L zRqjHI-$uCc#z(os*Qj_4>8|7WeI|19DBn?hly9utzWe&wlD|WUS}U4kX_9_$!1Jo_ z@N4@~MO4f0ABCbm_PFDSLQ(llLcXeas*2CWmqH^8rnBp_+uu<7Futf3l z(T@II9@R>>TG{1&Yrb^y4~Kl|{!_ij#~4MKkIUH&Ws)AQd{oq9er!7az^>yIX-DL zgFlXF(v7xbe3WQpTjQ0_ZikFK*@liYW?RGyG z)+!t2_m8?=YN1(f<3ql+1D~q+k=C&j8ZWmoXF0BfJudVMXes%lSe4XTH zyG)z3Rcyum+Qe6!pSSvnqJxiW#Y4VG^4q|tlS7#~57W06O&VXK0k%Z(P_*x!*m`(J z%M!J=pB;UXNx@~p9)9y1-AJN6( zCyqi^zteAKLc&tAs9Az$SG%@Z0OreF2w$amNQ_)HXv zu7vDR{Dk`P2j170PJWcE{2#tqmgZdU_zCsNsI?3m7!S>|kU#s;DDUJ4&OQ5%icV;} zRusx!BCg2n^1ihJcJT34OSe$G+{S$;_37lFU`9Lo!N~{UGf}9HmCx>jOW9}qDBoH% zu$vnn?OSx;Zlh5?lRPTBkLafh>9)5&WIr^D`&QzgF;Tpmjn8xkAGP(L{q>7ziXFDF z8B7tyqobNdob%@oBD{EOvDK|?$GbE(D#Ld4ZARs1 zS;%)7g`#e=7uKIY-)VeV`6+s4Y=&rGe;iS{Zq~=1*eKt5@<&8b8|9l$?jyeAQtLK@ zTD~=ZJjoABQ6GL;qH^h)fgfO4^Rbt%%h*fTAus(Tu0bO9CXT&yEyP~B>0>Y5)cQUr zdqr8hg~>&PhXN_#yElbB+!1?NnAQYu%Js zJ1!C%m9=i7FO(6R%Q0Dg2+u*Tdi=nXPLc0ufE$tgG@a=RCqLLmqxQt6 z^iCe-y3mgCQLU_eJmh;yzUckM6yK4>QaNAZ>!iO}ks0eFD(6cikMdVr6pCipvG0zn zVj*8Q`B^u^j>%u&zLsw-I;{8%(Z2B+_SnAh8KNEQ#LmkATcYe4_{qn{SZls+{72r5 zTFNNjnx8HC$-fyj#`Uq`H7;CFOqyEM783hqFO$a-CDG7c9b7y z`|;5X`|Qh8eSFjaTkdY0m*}%6`SOd_)*nYyew7`$?kGd@yo59bPJSu(P zKB67{;AqmQydNBeqFV7#(VVsX39Vz%9h~OqDo8#F(R##3?Xe^EndF0yhobU+a5QQ^ zJNml&e7twF)-qzPMWOf%={Bme+e9-&q4=b;tXsc-G-{!R{NO0m%4)?&W#$|ee;X8y zO}fzr#zVf&|C=W?I@0(FjgHi3qV-s1#}p6Mu_f|@qfz_W(btVX?Z>aRrLJo741V#V zkWVMCnolQ(X6?J&3oYa`QLSjlcql6G2m4XJwf*et&t&qqh0zI(my1I2B}%s?%ASE+ ze`f5+2iT~1tqePW>>Yh;enj$9ZnUo-A026Q06r6iD(~Azrp@3p$)j4i!BJ?Bjq-z& zNBN8o`PQO=85~yDx>5dHkL)(G)(!WO?1Rc$H`qtAXUtkRz(?YB`uRxqd|B)I_{gl- zTs?gxlZfxh9b4AAZc2s2@dJ|Y-0l>O$rA>+UGzxe&s%i7&ZDxwRpbo%p|LU9MWVBw zqnkaplsQXh?>1}y1NJw!ANo&o`^lmKes$x=Fkv(_Dq0jAy{?pukzG%RJ{jX=3 z*mn|LuQ?ZH)PB}H`_i%F33WIre!ggKzew@pj`qoWz?03w>~HSM?oguAe(|W|J5T;D z)vy0Q&7GNZ!Tpr+J!nSPqaXcGbNl(C0S8#mG4z{}b8ef~cMv~9P3(vIy0nvBCpzx< zNjcE@X6{z|zaaKEw;viEQ+&bcME&{sqA>?JtTFk+F;zbFx&6@i+!TopI>*BJUgKxa zoIQ8up|80g`cHHF$)W-KoNQJnd+u3>KDQtGPjes2$&S{_ce3Zu=k`PYY3>2M0~cIB zTy^KZP;*{ZiA!5_&&rxK{ldL-bi`qhmxXOJ26$v zuxLHeO|58Kah9>Cm}wj=R<_+H4m$g+1>N^FeBHOX;LCyQm2+(^c=3uWW@%gGr4ps) zIVf(kc3LR5^1F9hD%z}_R*5!irwq|%?X*#}SvzHlm2I~jQz|cbuJ)D^M?pFLF{$O>TQ**-cGW6q^iDN z-h826Im!B~CRx2E#7>s1-WihB8$))6Wc6lC*54ws%OtC}n%D-(>b)aby|2jbl&bmu zc1c#RSpLvoCCTd5CDu-|dOakoH=X}V$CJ1*F~~={mG_DR&T6i^=6Y@C|SK_#MVhxZ@pyo-Xr^|RNb%N zcFF4PCR?aLs8>m{b6!`ndM8R&uNT>YlGPg~S-ojwFP5yo8;RW~S-r<3tG9{l2a?tM zSh9LQlT8#1^~y-r-!YQaYb05{E@V%atln9Y)f-QCmSp{1MQkZrE~Walx?i$8&3dw% z$i7SVd$NC!-AlG?q0sYDl2xuDS>={wJCp53b|~4AWG9ndNcKjuw~$>!_Gz*&kbR%* zx9D$FvT*467}OkfLxa#HG!NZ`R-)(7yON#3?PxbDrVlC0rlN+Do&C;e0Gfax2K*z=P9Py22r`!(6U#7b!@8&_Sj*_ujLuPd>EXrg3$%q6xMt&(itXNbKm z*&bgK`vVoxaLZPatb<09Rq2BIqj8drn=YjVuzIq^^TCNm)gYIpwq|>N7K=KbQ@ZOUX*O! z56}*>S*Wyb`!=qIWWBVM?08QlHiXy|bSc@J(fyLudzRRHlGXc$*dAgf^f6-Ds*-ik z7@dU9Lgz>}$Hl~Ml&s2q#GWGdCi_;Py^Hn^+RLPY_te1M^B*F(I@B^ zRG?hwpaQBd=``s|?1qM;S?D^n3cY|nMn6k-l!qN2bOfr6+Mv_WaC9!Z0^Nqzpcl~x zXa~wd<;sU%YND3tR5Vbs)ksI@p)1f*v=TjmUO}0Xt;Wyjup>h32vi%jL8qbN=zO$5 zO4WHQkXR(?O|LU}AK7(epCtP(*^kM7Np>&U!WBa05|UM}DcNx}A=`@V>0}3!9YOX2 zvh&GaO?Cy@wPc?l`#Rar(eJ2m#n4q{bOLIRPDi8AY_tg7g&sw(N_H3c2>pceRSMY( zsE%Z7bt3A8($EaFK(aY*MQhPZl0MjUem_LtOEyQMa=0UvLB~jzZBDF*WOEE9JC*EZ z#Fn53B-`UTV($|B7X3}Oq`vL9POC|FpKKyoFDIh`XabstZbB<1>)>hh7WxA1l5DmV z{W!#wiW*ARRcFb1ITNL$3(z%^&3iYoCnc-AiR`CjeKjyG;6(yVPc**LuCDs>> zmTZq%#I8bjNVe}fVlPX!$5vuHQGVSPEL&c(4r)nOr8Vk_hB0oMWcw~8wv5YWMY>PTZ~qbeI9L=tlrne{*tU-as6<^*5GK#VvSH2 zvIEgXG#A}~R-g>Y=6wTwM)nU>L_Z#|aaAPirM_gnbR>2Lu`%d;ve%+}B&+v0v5k_| z`$^9IA<0qEpdu zG#$-Hx1fj6dh{Op24$hr$An&LN%m>q9`#3)&=u%z^c32RzLsot|3amX4YBH|De8&_ zqKRlOx&f_1&!D%_m*@{vq-N-#3aXE~puUo=MjD!e=AvuRU1$w@9&MIvHNHlFq2kAd zY<1KWbwvZwG<2b)Ta2E4E|u&Fb+TK?ZX>&kY~EU-av{koA1&E&)FIn| z>?vgXk{v*H2HCk}FDH8k+55?^A^RfP56}*jh04_q{nbP*(Wz(%nu0DxH=~Epddcnr z@1bwd9#o=E7*|!YwQ7t`L1&|L(8ZF?aU;49Jtf&^_nYV|si@9=*~Fic-I0nOA9R#t z*#^WqNj676vSZ0!NbEYaT(Ui$Aoe=3PtY%93)BsrR+ftS{!Wmrm-gs%Gzy)Eu0*#> z*1@CbRrC@1NwV4Uoe*?5I!-F?dub(EFTGG2nt>KbCHx+@5_?#(IbI<9KH2YyCF+H7 zWh9&J7^#G>*PK{4G)S__lZai0mPoem1H_(_Y>#(|ZAZJw7ONjRs3uvJCg@}|fN>Kf zt9%i$>xtcqo+kSi`U34jDGfpgN1}R?_0oaZnUc+$PV53=*Py$}K89YCtllZmE|iUvzI$7EucNH)h}VylQfgWe|lCHe~$ZxT8< z8Z|;)P=7QI%|SPy6(|F}fj&dOp+ZeV2dPpi|GsRAdZV#uE?R=tpiSsg$`Y ztB8(AZBcJD8qGpip*zqz^fKCten9z~hYrf4TBtSZCfRD7g~p&+XaTwztw4{V*Cbnw zPtmWaV2hBgh>k~XQE!xv&XrPi-U=kpo#yCdao z6I4#JY)xWqB%9+jvct(vCpI75BH11f5nE5}1GIx|mSmllJ~8xCL$Y3)p;OS=XbQR% z-7HxL_oHXgJLoIP*5FT6qHTy(m8`4AlJ#;DItz_Q7fLqob;RzIY>ubMzDf3TV!t!4 zaJw*DWy$KDK&%t$Ct2mO#Ac&KlI?pJu}3A_<5gmxpkK%qXdgPLAX$|<=tR_uacPoO zK9AUy#BN7x$-aa>MBk%ChtR>{=s3xGX+^AuWb+OsHkH_AXbIVe(F>B*d!N|1lGXd0 zSjmndRt+_g?271y2BAr49=Zvwlx*Io(OYD}_N-$i77Ob+TWP-AQ&A*^=Etf0ZPg z_h`xHZ9%pZ*;B}lBs+=h46=*JE+u;h*>z-JMqAMjD1Z0RUwKpuwMISBFfIW9qq(JHC9&UD$tGib9^)W^P-ih2EoiuVZF zqb18Wl5CDHWc!nyNNg^;K`P-ZuOOB|><#o8+25q%evcwO!@N}_>$E=Vh|WM`(D~?U zsf4e04|*JJL?26bls}`xP7ARkBzU zUSYO!lGUq8tR*^CvdTkQ3 z9AXy}yAj<__F41}`U?GtiuMU}93|NiH6V79Wb>XyY&@|G(RE~(qbDS*_d2o9C9C&4 zvBIZ^SY>pAWJlf}osLGK*=P~EOR{+%MX!?m2>nDhU*9lW1Xe-$tBOcP_ETlFhM->@#HFCiW%c{vcaqSg2P; zvJM)dE|OL5Pi!2TBUvxk61zvTJsv0a2KtQbZ^Q}>4^=9mx~QFGUGvk!;@6hz%z;9nB|u8(Je-y%&jnAX&W~#IlH$9ucxN zBs=n!=u|WWO+lBUn^{kk z_bFm;68jwePPXW%Fz->Q0qP{#9Q}xmm28gL#1;`-j-DXpZ#jR~Ljsi+z1iN>P2XbD<_UX<)yet>>NdB=uqIaCw1M5m%5 zXbPH-Zb1*B_2@nH4cdcBq=#N=phl8C`*c9P&=52cU4#~)+t3=RXu^HZ{v!GS?Lc|Q zg>mIjP1F+gL4%}JRW6W7lk6E}HrdO`UPX2#*+?j+NZ9%p#*&$>{lAS|#0og@l?;`ssdKG(RaF zNwi6_**-WfB8Ht#HAS4lR<9c0&$eT~>Q#_c4Ve@duVUa}5q zq1KXB?n!I}nkiW?3yCe0Y>(B%HlQtJzay4sYN%2c9gA8>)>U`ODi0<$nb;+0DcJ|n z^Jp{r8vTWePYb;qE!n(HC7ZV^v4O-UqPb*mKr19$p$uYgOIGhoVt)`TGCgFgNY+7p z)DfM5#-TarTFK_U2R%-9Bl?)^&%_GN2pv?Ctb@A5+MzyVN1}5joA(N0cS?4=j}Uu> zSSI?BY~Gn+-g2lWY9rYkrx6=2*&Ne}%_nvXdWh_L^a0v|vQX)BLoYQ@Gjs|%8%;r% zqMOnE=vnj*`U>rpO8I+dh4X^yqm$7PG!rdCtI#u&oy)h;m*@{vWL6kg1=UAgP=7QI z%|X|qd(h)(Bl-;eh6L;b@ycI~CEtT|Va5~wG$X-VFcCxF;t|t2$+4sn1lKqWrz6-*_D>9$X-bHQnELbeF&{b@1bwd9#mpZ=&CAej7~vkqjS*3=tjxz0{5Y( z(3|Kh^rvL2QS`!~qfi6X3H6g~jQlFjkDWOt-b&@W^QTokgEC7a^} z$@Xne_H<&S(0P*WaV4?ai9L#5CHs+No&F?QSNZ0K*$zj?p;o9DN<%Xw>tF%86+Mhz zkZiX1(f25Eap1vS;&@^tbv>(9wfT~Z6W&|vAvS@SL*W6L3PPuO;J~}gVAKk=Dmd2V#)ShMeG@3 zZ=)~C{)LLq4;>th8c8-s7h?S-n`0cYImB*2E68S`H_&J3H&kdr=%5m+k2<0=&=_<+ zx*FYy9zh$?$7q*ipY|md1|5q|ME%huG#}l8)=5PZ?k62Dqitv>%6~-|S02?utx-=j z49!Ff(K56eZ9rSlcW5svdu8aQnq;fd0JTFs(I9jVnuD%FcSyDx>(I++E82s%nwN3v&-ab#zZolW*;vUihRN%jS@Z;;(g_6M?mlFcG}#MPnaYLazz zoMc^fBHNQ}U$PU(o=bKP*=xz(gC0j4(P!v4RA^D?suHS;+MzyZBsw2mEtT-s^PT7s z^a{#EKT3Aa^Ij8l1geeNpwlFqV>p_Q=1awW2e+U#lFjj=RLo~TKs(505i5Odn4^Yd z`!QZ7i6T2ThOZFYfI{ikn%6rI`xGv0F6*WdDp|j9<$vU_g-H7f( zPf0f0o9J`&yJTGzzCLtt6l#Dvp?;FhJC@jN$>vx@_Aatd5PO|*pOF29Y=Ij>2Nh5q z$ts^n>~u6rvR=+3cBN!{+)ivQdWr0Z#D0>jO1>L|4oAmHc15(3ta1-xLy1jA3&`Gz z9!4*q_tCfLZ^?Qoc~hA87|G^sPOKZTL1+@$dFUp|>a8U9oMiRhCAOW|Zd7b>=pYp} zM4iz9Gyz>C*}T`Id&xeDHj(|5*e=QXOSw68aHM3hdZ+{0zG$>$^Ufl6jb!`YP3$pZ zuc2*ZccT1DLI>s1@siEamRN7e<`_Y2Cb5NR8QIn7WwaIjfbuL29h61Kq86w-8iuB! z%h6KwAbK8cM&C=N{Jpc#EkUWM8S05fp*d&?dO))G(R1isv>ok6#cmCIq@pJ1WHbOx zKo_Cw(Y@$N^cMO8?LsNbLI)KjTaB8iDLNVTLnF~NG!NY**=jt1o>1 z_N_13z8#63fyPMI)%nD(CUy^coa{!)I{jF(%0H7m?Cvn{5vVq5hx(wAl67z{x&qyX z)<`znizpNQC|Or|?+G20Lp4!LbgE?Y4k0#OvN`6Hy@l*U#MU$JJ+j}B-9xPO^3Y2S z$tpJ^b_zOMvR=+1cClo8+(_(x^eowTh~u7W>}<41vU+zBdsMP|uM+!+*iR_meW8O2 zs17<2^+IWAhGg?DK(~@zi(Vr8A+hfz>o2h~bWldJ*fFR%*&b-9Wb;lXc9~@RE+O^+ zvFFgcWWPm!qmrvaFV!TQqY1H-C7WXau?fWHp_|CAL{Fo)&=+VIO1VFDkct|j&ge{( zjxIpgpu5qNXcO9w5)XuVE1(AG6f_*oL5tBU$yV(NsdU19CcjR0i&Ryy0*P%>F`wN@ zHcKkwW91$Uz0{PVvmjZ$lgajxtX_Y~>Ww3No@Di|BzBin!q2fJ212R-ZIJRttR`FWcAid zR__C{+a;^Fn^>{cpeZEs`ZaAXS-le_tJjO{Fv;poBX+rD{oN>)_Eqj9yH2X^ z*Y8Qm>TM#MDOtUri5<2k)GH&E_VtdDtiSq_)oUtQy{=^YNoD*VV~JfTS$|haR__k7 z_e)l9jb!y+B>S#Z#@E|UY`0|fimVOwsz}z~agx|r;O!gVc>b*_uOUdf}B3ZoxkA?oqN>;C;Wc7|G+fuT6 zrxF_?S-lC8)w_u76_VAvR*>AWcAJ^dx2#4mj#m5yOr!J$?82%Y_nwbK9{WC?_~2l5$Y9`tX@UQ`l~5f zy_UpIldRq#$?8oad%k4-&6TX)4P@_|u9K=x0`?gv?t)hqpE=r2{W zdJTznmaJYM$?AJ1`0MzVSnC98J{+3O^$x18AH=mja&-&J0f>`s$Oc01Yc$!3u)_Egxn zjAZ-PknB3BMYajqlgRcadnVbjWT%mxMfOUvOUd3rb}iXw$ZjCJh3t1|FDmtP=(##- zfx4r?XfnD4Ek>)*GibA9XYgzE7b^Zt$R3RvNw$(*P=7QL%|$mzHpdE-f!>gc>r9tT ze1?9LY>pz&hAXEEsxMi#Be63in_~>w^T}RK>>l*EWP5BR_A#-a(P7Vp*^ZE`)7p|< z&+W+eK_k(*=n8ZjS|eEpFQQEJBg*@Hn5`VDiCRk5)v1!L%Mdgj%}2LLHt$2k)=PFo z?~(n6>>gsJ*N1U6B%7_7Wc5xVb~ZXkvdR||yAj7adyU?R# zUqv5DR_`Zb`Cbh5DoC~lb%>padXY^-GtdHbD_VmV$CHx z-X6q;5}S%HBfA7WAX&ZVh`lRWy>E&AO|0b0AzMwd)o6lFMg!0U$>x|x>?XqVG{+W9Xm^Iu5l$Jbt;RSs z3oSsmpjGHe^eXyDD(YAFCsg3|5UYUdpc7Fql!m6Gi=U$Qz;ODyTl{i29>(Xb!qoD&f!IJ?L??5q*q)lkA)qdNZgJs*Bp8K2ixk$4GQ8 zx>_pkvv;CLB%9+EshH1Zq94iTeJfper-beN+VsA3;bF#maE&OiipfYM8S>;Z|`k}Fs^)j2-BFXl+i`b*+b+Vrj z`$e)U1vUp&Ky@U$B2JX7axY?|h@FS7Bzrqri(Wz>qVG|@_d*AUOE&LulFi$SSPx=D z(NwaRp<5+8wugzmAX&ZliG54#Z&dRA&_OlS9Cbs3&?GcZvUzVpE6F~M-X*)8*lx-C zE4C$ckSbZMA?i%_Of*5Vc`qV%y=42|OYBKvo6x6Ze?=)Dgbt2G^(3341F^o6%`uwT zEMixoyU9L=UPIf^PL%({&_Q`r3$;bP(FimXEkw)EYP11uMZZX;{Jpct)}U&rCF+gF zqf5}O=wZpO=NHiX=v$P?4CBh6V^DL{4Glt*&^)vRJ%FA=@1pH!H!Ai~=%un`t5FxV zM%~a^XbhT(7NA=tTaAa&3+R3HE&3ak+!ppd1~o$+q*R@^0*RBQlKu>yMRo+)bh5L_ zUQYHZvbU3cknB3LFOhwl>=v@$lKqYBUu27Y9FF4%$$G9LS=|Uop!3ny z=uY$qdIf!qeny9VLRY9ZYJ*Ob>@F}Ior|tOx1lwXo%0vb2WSV%LghXUbJRpF(W#Ps zb`L>QB%9+>$?ixuqld_@C-$CX$MFr>J!DIK7V1?+jV0UT6k=x+I|p4%_D0D%y-%{P zo+A4u`U?GtihdqCI0`k8tb>3*{XelenADk2-(V#&3gi| z_L9wUI@wWV&m(pv<8CMWDA`wueT06Jta83DLkEYW<0R{)6|r8D?U6=o23kP&R$>oJ zR^=$SkO8Gj>b|k8YI!HF}nJAs?1?U>GcN2R|vi@Ep zwvE`YsNgrDgNo>Q$>wcKthZ$KMi84x>?(8z*>&h;v=#jz*&KPk4IPw~Y>ryQS`+Ju zhLN3yE=NnzgJ=WVg1$q0QK|1jFV#^~)D;azlhGw;F?v|CPy1KUr)UoSb@nlaV+m&oj zvO~#^BRiSwJhE4ly@BjXvX79>AiIg|2V_4cyOZo5vUz_BM^sL-BdUqopwrNBG#$-H zx1fj6dh`L>fwEBPo#8G}12sdZptI2w$$GvN-Hh%>&!Tsv68^8c+5@V%JGF$9-g&(ZIa?NRubFk5BGVke+ZWcx|QeJ^7r>uNUH zMd&W{D0&rrf_{-~wgSHfRX}yniIUCM3#Fm+Ba`-)gKP$!7bTSjpeR9@Ql4pb6?mb`Y^il2w_9 zZbB;=_q1fayhUs~vE8WHt}t&ZYKS_cGf_IaNU~n8Cw8x7^FB#z6R}UxuVf4U5jr?h zvU>H1b&#xHUt*()%|cg^y#qalUPIf^PL%)8FmHKOOS1FP8ucbSg4j&S`ddhB8L`!9 z1KBO;2g!~%&+af=S;^`hORNR4?r1RC$>?&l6g?=}9M2QmEZH1i6Z?x;@xMa0x@2q6 z6m>-d(L^*C-GEl0XVBZ|OY{dSvM0=21=U9#QGYZ^D&_B2^U)pX3G_Dl9v${~*!M_O zPqHKLfcm1*=mK;Nx*I))UPIf^PLzLdn5`l@9<@ci(FimXEksKsTaEis26_#Bh`vF8 zpp>jo3WX~nLknD|QZz202*{8^^C;J}RZ_pl8B2VbKDr$^Q zLT96M(8cIRbRT*Oy(!sU;B)jRDw;QBk3tP3TggtS9~z5hqw6G_V>x;Py)M~j_b2EV z$>u1KFHdwws(?5|PcitKr0uOxOmS}WNeuM+!+*iR^5{xI9&l688VWcSHd zWP6}AGy^R_x1xt7>)-|SKKd3V4hyrDLC2uxl6BQhvUM4RCZTy~iDdIWK!mlb5t7Y2lh{IHcc67-Uq)Lc ztM>!3JcUEOvXZUAvBX-Vo@9riY3Opa6g`NZmu%iG=sU7|QK^(LuDWEsG?nalyAm5n zY%;op>|(S^vU#5&_O@j8z9jYsvEoHS_GrmEXoR|;{%D+JbIc)jtz>hoAeKSw4fGk= z-%z2VVctrpF6xNRKx5GP=xTH)dIY_KK1M&I!-|CtjzIM!`?Nm^4MyjoYtc%y9&JTG zNVdB9iwBiQwNPu+6AeSt(B)_uT8%cKE$BP67nLdzdZ~_DpzdgZWUDb2or^9uK=dM+W^yyYaDw-(tG$hIWgooqj{XOo>s_B^r|lD&@Xa`Y5>6Mc?;M}Wt2mY~FNY7f3e8^U730f-Iu{}uadCBT+ zCiXS4zfkdtp@XAQQ`8j=L=(|m$>zNQtst9$-X{Acu|Fj1uSliPK^4hj^-)K%XP|MC z%{zzKwUX_753$FIZA2fF{TUUi96G3k>Pj|8J7Rq#n`0!gbBSGn?j-vNdIe>oA5q>T zLkHzhP1FXRhK8f*Xg<0HJ%rYy5717@KJ5!v2|5}zN2j55bTL|r9+d2QejaT`U!%RK z)KOuN>ZmE|iUy*IXf9feR-tFm+vrR52P%>pI;bewYSck3QCD;(8il5#%h6KFR^vhR zJlc%DMt`B=M~8i@qb8`GWX~X7Bzp!qlk9M^W5~`Tdnwr~$Sxy$KiM^8H;{dk?0aOt zCi@H7KgkxU8jj;|$$G9VSx|R*&XR7^Z?oCh`lS> zacn2Mn{2TfpbG9l}jBLdZ{j1tSRbB zb|9LFELhw zL%*RywZm+cP+incvU$%yW5}M5t|ogYu}389?-gR1#C}GH)d?LOfoe-OZyRE#Nmg$- zvFXIFK(~=ygI+`*pdFIUkwvWZ@nMddlAVQ?#7;#+$WB3*qMOnEXgzuleS`L(5_QA8 zRZ(Mf5;_~5gDyrlq6a1Ww0{YGjCP~aCxmgePNG3b1BHM$c$jy9sLlC8$K=ucFre#llt$DwAZ3+gY~YK%j3(G6$?%0O?R z&(NDWURztFEZL+P&o<#OkvV+NvC3_Cpxn!>-dmY&oWY>~?g6u}J zZ;}0o?2lx3lT9=XM^r|#BRU4PLOsw>G!Oi)yWKS8RCF^Py*{jeUXdQYPZ9_XHn=OCSpz^2|YAxApJ<%{U zQ?jlWO15gt&}y^+ZINu=?}+V{Y>u+cLiSk6>a`%&U9xe5$xbGF39-fKLCN-bp4eve zwPd~gMXY%9u*cDob#M((#uMe@2#Lh)mki88(f?h$H=tq>d zRhYLNswvs|Xo*fEJDk{b$@-g5>=t4Vq4i|nLpvlp-YjCJTZeizB6Mc?;M}*eTVY34f|F?btOCUcBl^;iOxq?qdU%8XAtKqxopDWUH|fJ%L_9ThMm&J1W#ZRH-D{YScyTP#-iBor|tOccOLZS;?Mm zUX<)-C|k&WPWBtJe~~TFA?#aJvVE&a)@dEG4ajyR+k@=sWJi*nM0N(*`DCvryM*lh zWS=Da9NBltZb!ROv5ukVRMZf4Mg!0UbP>89-HV?eQ|P zt;BvndAfwz%1YMhv69^{%|(kPn|BqlXC#~BZL(jI{exJMlf$?wlFimgvU**J^+)3*t2~F;wdfwn_I;e# z8-&E>Vw8G?tIBAUrp>zVvnF#$Y!D+(P5{Ad5=J~Q5(s6 zIgQwG$>yC-Y(BBu&>FHYq7Njiw}V)gWc5mS3%%5kEY=d8N_GgEf-Xfjqx;dblFj=b z`iATtRHAzrS5>m}(O9xxP9k;|v2)PHWN$?GNjC3O#NL#w-si-ACsy>-kUdJW4jQ0N zs2>_D*&MTpEs|`G<;0#K_B#56>@TQ5k1%fqR0p+3r=wBmJai?x9j!$#p^wl{C|}Re z!QrT`WS{n((b;GwT7*`h=gi$X-MCZuBJDgg!;TqJpP~o-3l`QCrj(jYhN3Rg&EW?m+9%%V;awDcL#C-#4f{ zs)bsko|4Tm3{67|CHw4NhE_{9#|FvnNL$c%WcLy)bw-%uSjqNnA=$p&i48`RCF|-E zVvC8bLeG=kELo>tOIGy_d5=boP!}{1O_Z#Ix#$M80%b@x+Z*UJ^oL|!6*)6> zPzBXT9nl$*%{zwJ`I60XE!lg>K2B^S<31+)GugxXhYpTFbtS9Zj#wWwQnFsoC3b~m zd)!8B4SI!aCb1tStCIJupmM0DWLHE>$ts^pY&fy$Xg=9n&_ifFdJlbrvLx%J^nfsL z4aw$hM(h+~XQOk-UW{&*tls^^o|UZLJH);s_9rSjFm!MfYK%@oXQA=vLdoX64lO79 z1bUO~=fr-OtiQr%hYl)B7CQm8Cwn>?E7`oWi7k?B-@AxCO6*ni5!s(mfkB~z3aE}` zbDT)5mt=FK5t~750lJ;+TJ#e75PgplgF^>p&@reL>Vbx$spvAa1U-PBL+_(+&|j$7 zkkHFfs6Og|PDf+V`I4>L0;#kOZj`lx!uRC;O&U#_#btu|FlNS8!;k zS5dO}Y7NQi)t0PY8?xObt2c<)B+2T{m8`!T$lfklz2%bCdxGrClGWQv><7u}?UAfr z>0zP2BPFX>O|p7T$aa*h-WkNkNLFu#Wc3!1T`X1e>$gm@daKDkD_OmFhfoqEhqb!Wc6MnwoS5nJ0z=@ zMK&cZ)GH}jy=s!3{rZyC>q4x*Wc5Z#R_{Ermq^w9`Yn{K-ZHZHOIGh$V(&>-?+eN5 z?IN3ZM5tFtvU-&y>+d+p>a`-)L$Z2}<*UyI8V%HA4pd3 zN3y#mtCtuV>XnhKzoR9q*NE5?(&7F+*mG1+e!bTJgSGo-xB2R)?4G>t-EChZ<)cJ5 zw!Ho{%aOlL`9eOMNK{h3evbSO<@0NV`*L;avbKQ>W-Lsa+{|P!;{oRo0b`Ue8_Y0{5+{zovLJCQqW1CQ2kywCtTqm6P1T+n0OX zYG29@$47qR^-u0~zZq^;_f{#KNKYHD3LQ$hWpiH@*SY_;S?yv+NUmxvAFI2%iXZ1@ zO(d+NSJvF9vGvxJNUU2^O#jq{+b56T$MP?)S)Qo7`h+zl6Hl+nPp8?PS*NzJzO3)m zzm7UB?$$@&<>X0>pD=z{nm>BC?(Q;i|1YND=-oF$_GLB0rJ0d`RQ>Z!2uT=Wq zSy^>#XFt}z_G9bJaA(A=O%!>ixOkI%?4-oK8b?`J zX2rVYSS_|hEJ{p;08);)id{QQp7aZ~4Z4{Hz?~{p)Ca5v}OBlJ3$R znr?%0^fJr6-d`_PyH1Yb{`G!)u}f=Dj$ZuhXuP{rrn*)VQ^sXqDqs0)y=3yGV(Yde zM=}3;zmwbhuyT%O{pM9jirJD;JmhZ>{ z`HSW&SfF6hf`tndD0*1&P$&@IUZi z+!t-b>-ct+atHe3_WP$luFeYmS*btwMBDqLZEo&=zAkPZ-Fp9Twr=15$)EVO5WK(r zL(XmQj{dlD?!1R{@3t-<;-OB6g&HpIYJ~m5xcD}V4cjn}+q!+@W1Yhs@g7_(%n|Z# zY>4IDFVqbAFn8ED#N9SH>=WM}Z2ZCU@mkKIj}SlD{s+q+YMn6d-)xtw?|=I9Z)zTB zpMRRik?k)zVDL1&kE}j z?!WQtC-?ii?C%kCJ|~8C3)}d*xmZ|Fx1W2RbN_?o<8{OSVH;|OG5>b^U%VF%b?*OS zuH4VN+|Rq5*IVxUF8A}!T?6j3D*S9Cey?@Td9QWXP>98^pWM&8+|Rq5_m_YBI`{J~ z`#lzaUdesmWxvPb_o1*x@q5?)uD$sE>QMF%>wU2LhdOS5Jsm9eU%VF%Hb=<+7jxx4 zXXZXkFY)1=g7hGp-$NT|M7hndOy(C9aHY#xyinc z{)@kFix`jdOE?7knKAOE-K%DpFYpRaPCuX5fS!+SQw-D~G? z-R1ng=wSIntrN!mo9%z`y~d%=`(MnJ`@YM4-{rjCa^H7$P2^mc@H+Q>m-}-(cP$+3 z^X6dra6N@>?)xtHedn%$+@B|8KjVe>Mtpm)_tnAj@mkKg@4MXhUGDqN-gDu5tDNtV z@IGi_;nE8M=s{xJMnA9#o~X$*s#rg-(|1Q!QNK~%ZGJ7)Nx__|781Ld=*xCSX#fzutljo`UP8u>-SC-OB@z{Iab>E;rb<$yc{}nO4?-o8Y}`MrlzOscUAFv z;*d#GMh{8XFP9{gHh$Qkq3IL+FNQ1Pe=(x_m5cTZ7mJi~UASL{=zbMq$wU$V3mDz6 z9JF6JSX2@BOZHr3m>SV|^|)PEhW}-LF0e|!DdG8`8}6r*J|nm3$p{w{cNqWcd6gN580SKq=_FgD?3oXu@<*Tsae{| z{gyZVjyE^0`z3ABAvE@T?1}AB-w$!WN-Y}Fzz?aMy-)pye#n6ANHaeqGkc%<^>kW$ zluG=pwQTEupQfNM_j@zzX`7}$jiR`Ir|2B_yEKo}wt=>FwQa8L3EKA7R^#Uk*S5a4 z)3w!@IrFt`sO>GDLan)V7qit+YK# z+t%71uWcJ`+i2TXTm2&riFVo!*0#O2=V;qO+l#dAsO`1dcGC7PZ98kbPTMZpzM}2P zE?+Q_I7Qo0x|q6aJ46T9L)$ad#A(|0R8q$_r}KbB;&g3K9G6I(p>5;YiNu-O*1al` zI7{2=wtmzWjkTSo_)cxz`N`7Oou6Wl*!iiXtvf%*Y3t5UQ*GV(>7=bY zKfSee=Vzq0?X;bttvf%LYwOO>&Dy&2vr=1keloOm=jU~8-TB$3tvf#}Gwl3~e%;Pb zt!;LGzW%|^&kFs%PIrDrmdxYNPtBwA`1A8s{XG8sEN`F3pPw}Sn+@*#jMwjucIT&= zey^oFKmD}5Q`-mmRiZFLIgJg@CMZC}y$YHjQ3{cydu4Ya*c+s4{1*4F*HSGS-0 z{jzR9ch@SXKLrzyMJkfeA^2E||BbmWTO{!(vBPvFTC8xSltcw$M-p>azKzqNMfF+} zYe!7~v`aMZG-4BoO(r&%*rmj7B({Xuqr{#h_CB$##I_Urj@T|@e-SI6H}qF2Qc9vW zu@i{3Bz7XPQ;78-=6=htt;<+q(}|r&>{4P2h%F(ujMz$I4-$Kl*fYdFB({y%x5R!R zRw7^MuS}$r#IeL`6FZSu2V#SW4I?(6*p{Vi$h<#0L2eE?s9JVzr z5-BB7o>(Pft%w zs2eFI(OPo9R=P-{U8I!67Ja-}f0>a|5^aY~7&o!*=;4nK$)Csl2IhQ;wjd5Mu7;y&%OBkt2Me7UojNc^!+>=N_ldaQn;*XNCbINu z(1Cv6{rDln(g)3$FsZ>oh71`${9r>4US!yWi8BvYW%8)0BZeNN88>G5LB>p)JZkia zDNPy;N*_ICN_v{k_UIww53*1Czu0HU@Zp1|jvhayVS_OcFdm#O$i8s{EZ z+}A(V`!0N@*w6#k+o^G{y93f!sHanMLdQ;>+nwI6Pq&lXx2UTBbm-ovYI3kgw~nW_ z>)xq%)l}E{PW`!0f6^0qN@W=uT^{{YIqhd3-zy-&T=x|4?VP8%|5*r?Rjsnyd)PfT^ev;B+7 z_M%a0ZN2oz`+y%N!M`mAh zk`^-dFUbr|8!=&0+W2wygHiV**04*C?VQqj%!+;jS1*cUlPPQf%b8BL;|GV#U+=pTESNvnp zUGazZT~2t9tZu(iH&a(M{_*GDA^GxrqW?O%FZ(Vh{?X?u-MdqD@tQB z_1{pZfLFYZyXPIOPT_s(6r!TL^SG}9iST{TF&5Cje-$F(yDs~_=N#n^_*~Ds?0_R; z*W3ZeB;UhMXw;}d{n$ejPg0Fy!Pt{jqo&OoSjIg`l}u#nNor+r{WD(Cf$i@}>blss zE`Hd4o}`}Dd0wAm+<~5?=7x2R=G@j@6 zNuA}cnb_C<>bG$_!rkj0Yn8r+v#vQ0X{RBL5fyP|rt}}hP7WP-q zwZAzUY8$2?lHIpOHY2ttXczI|~mmdxo_SuH~FE%@K$l;^6w;VCpo-Q-oTKy+am&ph9KYXBc51Q4} zhE9w>c)Djzd-zm*pC{2~`#y;-)n~A~6YTFvbgtt6`F9FAoX?Fk^FBS>LWk=3x~t_*ZN#h`^uvaqK^K5l6U_mTQvpqB!<~PN@)MA zVRSF@2{+WeSF`^CKlhIp+PIQdk8$oevd4{OTsS^Ak*nvv_en|gFQvmvbk#BZ^8>W| z+W@YkR2@O|w*mCZwe6dBX*WTtx*4B{|J8x93IFV!*yl+zth-ysa6Yu2bKGnFTa|O% z+G>n{(ySrdQ9K5_3NXwOA%GEkqQ{A1NhqF|o^tJ(j9n z4(VyWuLioWaP171TjjWRqR%#ebH1KyC&za=JYD?rS#e8yC{L^Upqisr+`sfW=P+$` z!}jZ1Rkn3?vUPPzN!+IYTI{Y!DG9yD#-wJyvkDDd?{54x^=JR@EcdbMzT9fKueti; z&Td$p+vFBGR>$q*#<;8cW>zQpoi#|SGg5zNCHoDQeU*o~!d33B*>IKDQPF>1&-hht z7jDkg4aekqtgb)q>o~2ZdtFOg*LQ7g-MjTz{jt?`vek7;Ni2-AMf^_~EcOYpFCyvt zNcSfFS6ALp?bs&A+QzTE8(7;MS6=L?^`FJFA)|IK+X53{?W?knf}afo8A|6x^bJkY94 zoTQ&DO&P8Kt?5t}WuJRp=qsP*ukIStm!_KIwz_Tl_oTif^sD0Xwkl4xDo(a47IUj& zG5@(&dH)}MM+{u=ejIVM{_Ot^>YfALm%GZ`*IfN^E#}uB_tAHrZh=j6ESKBIjX6?( z7PDMA-k|#5JJj!?ef(vAR*mDc%Drpt%RZ~zyD9r)a$Njl(xvRnhPpRkcFF9I$^C!) zg@0o=`vwx$BHTdS$5gn1oTB6X=kp)Gf&72$eF=P2)%o_BOg3f)l8}f|Q3k{n!GvLV zAqYXVpdf-MUpB#5D3|KHd1%gs6WIm%n?pQoBFD8eIro z$-5q0ta5=$)7Gv>m)`yRC#REzn10_T{O6cVlWNz4qYiV?^v(w(lhffS?DuhT$`onT zu7`W~geym9_hj6g755~k!&Rf-_X_@-`~;-SoetSqrNjJmPTRdZIUQ0ZKAlifI$SOK zePn2+^TG+`^~vdQx#{n7H{8gX`x{-6;d!}M`2klEz@IObC3@#@ZB3rvZXc~095lO{gI|FXEH zT$yb%DR7=FC&saJ$Ambpkv+l38QtPN5>xj67^h-o)i}Riptj=6rq|6BLx+|PFDWY; zbnd8gOV2+0+|ebbBtv@+8&-ld!~O$2ce>mlwhzpi;h@Oifp~@CPFG0$6+2yzW0i1{ zCZN|&*KVKoG?vFs*K^>fqfKq-aH)2>J~6G!9nMwJggIrt#2LM0$P!Uh;%-6&DKxtZ z;lgZ}Fl^vnJ4ETo-zx~SRkr|66}@(xP6U2&o)9bX(D?CqrFRp)`*VaDqDO8vd9U;u zfKv&ew;ncAr8gHI-$9t)>BCz#Xs`6T1OEs^YbVMQ!LVw)@)tr~6e3Jd)GZB*&Gb<5 z2eOlN8=_A;SUX8IRkP-Q`wb*H(b|rD9*gtI@1bgR2QUL?TV)VqSX9}!fB)jaW!054 zi;K!;R-zYD=a|*{Ad~MT@8TJ=%d2s)*$wYSPCB#8Yi5_#%r5U=+?T%*Ut0;9X3PBs z3ROUSqgJL^ixiZQMJ?7d*?BiPDR}2(R%O{j{*-ujUKmlC)*x3>mDSbr7vMeN&=rFP z>O)n3uCMovr~dKn?>x5a(62k(`}x*JEThhcU#{=1B}ctPMET|3cc0hn(!r6wKY?Ui>6e~pE0+tq7u$NMSY5k z`u2l8rEW%b?GzRscG+T_Oygj=&+KozVF#v}QduGEbc(FgDUy$7eEY1rbJ#wGo>w_< z#=^_XYEbF}-XuKGh~b`nu`P+M$^L_i!oB5YHmrwpRp}EG$L?U9YfE3>R~L>}KC!3g&``C#s z_bj`3a>JV1jvGV?D7T?Rt^#6X_D0r3o|nnR-kG|NQ!2GZbUIvI78FoHMb6C%sJbJL zk{H*)%5^JToVgT;NARChj{>m<|GCmF5S#HIV-Q^L;(t%+;>Hu_dIcgAQyG=Y;nr0I zmrCzcxKt_^z{S~HftU{0@zNE83!@$|7KCXo!($BRh~zA@usIv=bTcfcTay#~scw=X zebtW6g$e#I;ys;Pz%Web`~?3#_!iFk_)kts?!*8(JYn~Td173CYpI??!ey5Y7~RVB z=vG!ySz8VP%nBrFc7ia}Vajku9+`{e6XH@|CowD!lMN|3!wDbXIUW8vy|GixcNX_= z^8F^eM?^9x;~b^r@hAlzK7lV`m#A!^{2bd}Zy9!`ue1IfYZUVXUr?M1Y=4ei=E=0! z+SI~wvdwytOe<)!rf5je*^@HcR~^*ePiHY)p1?5BHT(yX6Dxp=C0j&D?6pa9g{X{5 zlHr1+D?CuzODvhx#Cffa=(V5K84+udfKM!}uH*y}m1JmOxXt7}tUsg#{>rbAXGc$< zNq0gb3X}^=iL?7*t~mdM7G8}6*_*NSD)4N~#U#we&W$?GG=(@%V(frM;!KLA?FRe? zu-Hp@;qx+{lkv;}J{!+e4}bbq;kh2+x{A)ZY(B;~l_HkL>)dv7oo$gr^YykJImz-7 zH|vn9+@4c=d8~q?@yNYAs+N*;tPj*i0bav+C6yf-GZ0BfN`R8oxh2K;s%XdnBp2xi z>QOM7bqpbBq@I0bH^iWZ9Jf7$ou+bAmOJQT(7%hX1 z{xVtv`y|-h6+~-^-U0h$*pI<3hP@tkU)WnyLms0GbD}89+ zYO#M=%m;>5>E&rxP#j{hV=Q)p#m=_aITpLvV$&^ly~S>{*a$E$n}l9p?h6AjDBOQ*_6FH5wwpq~jTIn>1<+!m%^T?FYiJ zJMr)=I#KwMaTtapCc6V=yhj|hMxI?Yzp7Stj$P4Ad~8UjbK{4UamI|+Izy9D(;1RQ zJE4C91;vYK>Fk%-&*(%Gt!QT~fYrGBzGt zxm$RND{<0{ZY6%tVT&YgqJO>2i)phfG%||Kv#guwsKAr z6hG6hfOy7Y&s&V`nzbDigS0Ck=MpNtNx)Qkm>P2)oP7c2sr65nTmZ=oGn4GfIczCr zuk;_QP|WTc*3|W^Us6y~chun0!n(sSbH-#ZSihm9aZvqc(Kso+?Bd9p$y3)U56l8- z^ek}InI&WA2$NK(e&asO6{oIaC#WWLoDz1&Qy|AylF)nF)c_wF5}1Ze+5t9shmRVq z9sfJhoM{&;WC6J-2CF>eCKh^W&& zu*OhdoptvhXC9jR-)!QMhZI;a=27R+HBB(Q$E=d4SVCrKE*_e3LY+mQ4;#C%QqO-F z>~g%1f;}BJ$yxz>66{LY7s0*|Ho^$Fqw`@;fz5U>6*hU6;rN{}9yPqvrG|I90%8aL z(-joW+7%EyY*ZKz8|ey&J{Ie1v5^*ITUFuaTZ{v^!fvtH&n)(!#dvRp3dfr(=n4vI zA}Z`}7W=!!c3SM87UKY};$~=9K=iQKu@x5Cb?Q1+ zAuHSI%zEO@nC{xaP&A1n?oWKYG~!GQPL5$5KOVLmQCi{hCuGNZjSxA&`oT{reLtqj1R&J!dtwCb;GQ(eoQ@|g)H#> zY}l-`@94(Huxg~IOO5n&1;mf=UtvGdu7G&TV$WFYBa7{{SfS6v?W$b?DI%%TE4A1g zHrzIg9Xxdhp5w)v{W|z}o!*gG{k|SLksaH5bF)Sp!^bjAoGLg!>-TZR#Vw1^wlqIM z28tIK$dqAtl4p|4kTW;;nIPxVejg_#tjX&ab|0Rc4x5MH#}m9DTr^op>2Q+Z_cic8 zo;_(#>`P9Eb2q<_CwFQz<Vbia=$b~$j-1Z6s9 zI5wEKK&j;mVUEnP64b^Z=NQ0-nU#cmHwn2_BOPq42Q?D3$cq}uvIzN?Cc`4RK7}|r zLO5tR>5v*Vm9;K}&K))k5B|Tx+fZlPUox~9$LB^6z%{wk zhk$Z{Q&KXxWUxJ;cb)QiVP$ejWRi3RE~{GzQT|HLI5Vr}<2Er936lxCwdV;sgF%^B z9CzNKMeJ2NyJ2X2TRC|wt6iYfx!Md{GoyTNdG)-yxwU1}p>AsP?wxqe3}m#TZpMCu zLz2)<7iCJtmGyi@W%UBlivGEW@^s+jegg*g4Lio_{G^bC7~Bu%VbV|%qLY+_I2H{# zqB+b<5@H0}Xq@qogt!&mR82y-RFV)m>}Fg>hD*?PUJjm)AzYsBtT_AjI`Pj%r}`km zH0e%+TfJTq1ej8aUmy{`o~y6{d8L<)GIT_kL-fpr3qY^*t_99p-7eM30QQ$&>74|R z?;*?|m@ybmi@nn0uE%N&&71X1B31r2!Q*cT^FN0(H6=pkmEKbLos5<118PGTy@YrE zxQo9YVG56AYHDnd>AA)>;&&k2avg^6G$mqe30UbrPO@Ub!pioNtjIyJ|Fa}39szT< zD&s-PioOR?2t#VVPeb*CG?2DPmY$d(@!Ma&>Ap^f4!geT(mC%`_3neF@;?$!mfB!K zxxQrSj874M66Z|qCWYY=NI;tVclCg`Rz60v1ThTBbnPI9;VCil?c_16WXFLDQ+#{L ziT0BQFezDS0O#=kK#PZ@w5-VB0Y;FZ9n-Qo9Z=Mcq9``29?1hzvLXYDj9kXIufq0E z$>!YDY5Qd|DQQa*hg~?S=c0&`A~&LcVproODRLR`gDoi{NhDQ)o3suyw&t^a_R&sK?HNDylQ ztTR!+zG&5$H+sDoeERdh9`VfQe=R%f;$YKc3VJwV9(a?R{E_D;%e0K>2aYJg5nM{2 zfTw^*kMgZRZU`SEu}AQ~hjcxK|C|*Sh*z!aW9#}FE_Iw0Kn-yDULbnFr9?Wo1KCqz zyes#3>EZ@kcj=k~S1;+h+PcW0|HQKlk1?DmlX3LCQEt(7g(t&u&dH-lw?B{m++rR) zv~>H|!QY%WFrBFh{;$B_ecr&kHP24i0%V>TmwTt*Maxpg`_OGsWp&le%bnGql=e_t z={QU0*#S$Ywi+(-mH6_3sm(c-P#I@?(0z75NfGiJ>r9ApD{g@!Eto=^PPTmKKa~zQ zCXBd6!hRsVlyQzBoc+LsR0C2cCTiAQ<~zaH$9_kz6cArUX1Q8BJv23H!jqybACL2K z8VD{Ok#}pH6vQxzvHd4WQLv#gGN+G5T!IaY2NGQGpt9s`XEKF1km?YeQ+5P=J?ig! zc*Y};Tb{zmR8VGOCZ0+>O{lkZc)H?DlRRaNL$;K%6NrT^0-Pqas`A9+P?CjW5}-DZ zLrIldJdT(I(;!`>*n>=w6rs$+FnOLzQfLVY1|=0pmGf{JdN7YgCp|PZoNd$_OkrS? zznKlLIZazc9;ArG)v(WI7}(QcW1$$m6ZUnme+Bz{upfhs^rGxgzYqI0*f+x71^WlE zGm!pGusgxVW^43V*gu9n05*B7y*W$c-n^BWy5`DG44dGye!i$DN-U!q~WW5kZK)-g6m&w`E7 zMV?238)P_+{8{2={HH4@Zq=@Uc+O&*EVj*J+bzbkM-`W6k8}k@*kU~`MqvmQj=~Ts z+z5+}ve-0>Raop+xLAsy+?=5ccNf@jkJxZpkfI>=0;ZCM^-XJH8|pWqF)Z#^ol*bA zlZ$&}P8Tc9t$%t={g! z#ayD*7Aa)|RJeG-iE;Q4W$C&g>t^ypc2~xkv^X;n$O5p9vfXjk$$5r}$i77xX9`1E z%%cHP=)v2 zmtczQYCtdZ3nrw4q5=c3APj)A%BcWH=qMgz$P3IpXG)j>Nb_q1A@5zyx^3$cH zA?ON-7VR69dvyvs3@t~6J5sv>qS#{nEjH0&9Pd@!IToW_gu;GgF$w`F>`9BQv)Bg~ z``BV>XjLjNnc9ULyW#3B%faIYx^U;64flWzrzIM^?&`sX1&1IWYtUPq0sXx+YAjN{ zi601gZzmqEb}%xZKwJ*;nSk{a`ml|HB;9;2A5FGT?|*IWJcv8>vGUEq=Qo| z>)I8N-LZ5=bDe(@c(P;{`+2Q!~gX*{12Yg z5zoxy&3;K8xlYR2-2A@fU;(nph!q|G#fBFzKg6jBuJ=GtGyO`Ji&wY24m0BSO~HT0 zE?H6kkK}Z?kn;O@KF&dwCe?K#*TRo|$@@!x{=?*S*joKQo{RG=oF>(EBODr-pWXGh zFGx;@Q*c~=f&iR+(WJU=WGVcRZE^Dblh6$?MfY_qjP3XF9GofAsOv_&<&c~X&Pe%i zBBP8!2J821VUY0}30Q=Ek1{3$3yoxo zu&g^wGd04iO<0?_Wc;U92)odRqYFMK( zj6@DYg@xgAkio1%ZPLVOyp`#5@NX@UR3_JHCONmLQd#1h&IHmpf1$xZaq--`B;FxX zrR*(Ogj4+Nukw;n+KW!@A#{HC>$%1;27pqsk)XED;SO%Ug`Bj z+k6^fKG1U+_OM>*Z9)F#VlWx52PS^rE4`H%!v29Um++(whKoa{hdMYA*`vDaqYoSuwY=wz8dWcDV#3`nSm+^}=l|x8&`Icv0~}{NXDF?1Uj0&w znsDD5^S?#5=@$!^+%fiu+c*3q|MiX^lpfn8_jn+~lq}nnj`~X_+f>cD#QzT2Cd1VK zm2ax7Q5RaPJFKmkN%4U8kYQ0*$~b8`LMsF94JY4PFlk`F_LD+#(z28o*suKrg<4JC z5@%q)_Mp9z04pwPM@qXAv*ZERellile85tuxX8H#No@hC>G|lqRhSd78~VR0_p}Z3 zg*%Z6EBDmc5XOmp3>v<%sgQj-UcMCK@V9GYLr=V@J7RE}m8<1|c+Cy&eR1C%vv0K% za^Gqup@oAyZn;rc*Jyzy^#a)=Eo9`r>V`r}=8~L~kfi$jss`!Cojm4!E>1&TS(CTZ zI9MxLI~AJ|am8?7c7v}^w4YZYolNrG-ghI*yJ~oNqAqhzZs`-TRU|6Zq+^nXIeC7d z&z0rm4bO$+jhws@M}^^NrlSZ7*Nw&Xn?&QV^vD{BN?n{NCUqjJD-*hZ>f)6Gc~vr} zaq5N~<@zq(xj$Dxp$EM!e>+@U*B6N2;6G=Y1w7EuzAwS0eE$Yl7wNkb|5bVc45rG( zjarrR32>=YM!=k zdyS0VMfe2UIjfmfMg?!oN2O7lG)n24EJQO!W_hSQfn+!m-4FI(VE2dpci2cX`cK#cVRyoJ2f^+R8@r293Jwi{O#zWpVDr%S zRM@j%qtA$P**FyT-LQwjW*>3}Y}OBVUDdHMUFz7Fu7KF1eS^3-N`(uE5Mruux!R=! z#uP?@F%@^D4ad_ag)vtu9FLL}HpgP~Eq1-dZnW547W=uyC_bgqd&y#dx7a%t`=`ae zuviChsfycCy8?ng`Kz$*7VB>@?l-DDUt}@fjH9sm7OS>cKk&9nZ;*CL;kBjB_kf&t z;!zVE%ws|n>Yfu;*NyO!zKP0t?Z|G?W7S1|BfG6?m;(N`vl70H)w0fzU0#2D|nY^cv+3g?CdD^Q6SHxu)zY?2>j;=P{2zX^cXuGuJ|#r0*Eo(?P10_F3@mHB=4u= z;dn9zkK2C*{L`hc3O6dje>40|YCGZj4&KKl9JceD{Kf=4jo)a@Vi&|AK`C?@Fp_T zxpsvV3yEfolU{2bCQ8EolOGEsRSY@o?f4zl+gZ_+NhV#`hL-%qXpJK`QPKjWjVf*s zQS?*n&txBl;zrS*uny#f9pGjus)CVA_8p9?1moyZf^l>O#5Vj_*mmtwr=1GhV=*4K zD~xkE6}Pv=D3GGC=Pbq(9)(FIiIYHpJCU4OEM&*Vz1rCD%2$}=u3Zx= z?Mi94#)hqUmjZ8%tG2<}xcUwJ-{5Bo8-^n-++?yQXGH}*Qr)5c%O`VITnJ~ZfuZW9 zMBHa1viEJvX*dJ$zST@^mArvdP4BgW#WB*8>91;d!_NJ+CnW%NoKd?ilURDLRN_{sYxz^SRj)}~|d^$o# z{sAV}O0IDNN=XUp047B2=D7&r;48!xHgQESVk&p&{t#BlI(Bf$I&$T}27fk#idFcA zvvOD{u_KYDBfr>PVkbx}4{>QobuNib!T2p@)VE0hr(kkyIwOzW$zU1kHcMj67hxQc z8pC3y5M)^<#JzUR?yBU1f!zSdA+@wnx*_aLxZL2DJ~oC zSO$Cp(Fs1Hqf3yzi7RAZ2|j_4W{sw$J>Ar*;pcJ5i@BhSJQI=Fk9|>JuBNP;irKC) zRo(2#Zi!{#c*n9tN^;66!OdS=od|@jy#^IO5 z(b!5UA#}S)lX5&~rLh)KhfJUK#rm5K9u4NPp5$Q+>W#jvBQ@GHDl3Pzg}UM^tA+J6 zqei~U3ZZXb8I{CiREli{^GGzlk%)HUaEBoQZ1y8$I)tGXiZo~$(e7|fggpoLMX;B` zo(lU9u*+e;02@=vXfx~?usP^g!0wFnDq)`ldnW9muxG(O7j_lw`LK~@lzMKLz~&-g z0qh50UkaOxu4>q<9rmqi@j{ncywDYpOBRK(K`M-k7lq|oENro!7CXygV=Pu~u}X_A zx7f87qa3XI2K#LF-CtYmevAFdVrwn-fyF+y*w+@Ll&ngxvvxsi$6~w-Onvu6iw&{Z z=@u)q*bIv;uo$oGP~WJx*b0l4VAN6H7@=Lbs?lPTEXK=#RJer}+kuv%ux9OojPHyE z^A`50s`!0*x^Le;h=YidnU&?WeTs^{?-NmlxDU@k3W$uT4iQdk+~PaPEW+^UJl-6b zC>42)L+5)>o(Oj4_ub#hz`Nha<8sbEXi|w%v5jQnNqZ=W^>|`B%&gzXV{#si)1(rm zVq4@$QuW;I>yp#y03W}P$KyN_r%|F*`zyNS3@t`fs8}U~{{|VIgrE&elWxPrG~x(6 zt=34U4fD1}oRoJbAzTtDW4_Lo8IRN_ArB@Ye@jBxmg3WiBq6hsknbfSze_?kCLvps zkWVcFju4q>BSvP(CA#E=wco`{-W$ax8(MV9Gmxinly^w81~Og*4eZ-@fC^2itDuy++K7#dUbkNy38kqjDyP@Y>UqAwuY%(b3B!yGmmqaD7U2eB(`5x78V(v>QcYdaDf}K`{t}SE zq%yIWl+>@`eMt~YU(SDE;Pgz7Dl+v56UmXm%NL>xO5I1PU)!ohR#N=B76b+1ISmh6gO@bZ`4Z3h)sdghJFotM zwZHY1{kr_pokILp;>kBSeIfDW8=^i1{x(Lz_LF`(h`+C8c%dC+pX^0U2Se)XKm~)o z{iQpOz*2jr<%rC*r$~;K)AC5(k(X%~8673f)wf-wlT=#mLI{;qy9j|LBxUL6h=9dQ z8?D4J!QsJ6+GsKGf5Rh z&%2J?ICP$fCsXcP9|xB@a^rDD0S|7q7|JNP;`fp(fEdFGLr*+)#X)xf z9=HDx^qfY=o#A+Z_l|QN?;-Y)73^ag=hMdfZ$|@8-5(GkVV{p%S~P$#}!HB zP|P39hGk79et?LPxGUBfCvPMGPu>=zWahVgNFigKk0tK&aWjp+ENJqn8-Gy8?7Yd3 z+WoTt^_=lb` zx7ZGgbpZFMxE-|%2i+FyZn5DOJJVusSZtfc7YINgy|G?7r^dGP3N6oFEfRAx8wpOz#pf@#_s&e zvUyeW>uSm_mreE+@I>Nq1i6ZsigB3?cOS50(X^R5xB1V&GZxP|+C3ch*?7*xgI*<< z)nJTMq{QZ4=xXlqBsv5>?1NZrSE0KAW|o;XcTu=Q&unuhK1^=9Gs6sZnc8HRdheH+ z9KmM2vIpiz=Hj8jk~PXY=?9y=dVkn`VVA(hBSnGEf(@>gB1SkmidNu#2<&;V(VIuF zhJ7mR>tJK+F-pEEfz9u9#gl~`DOXT%DM&0J)>~|&#on;kHjA-$VT_<)@1o+ecTpI7 z7ljQ1XDjSf?eY|b(Fgaras;LrjJn_O+Tq=zM=LRy;aUtvUrD26Vzd~H4G-zx;bAT6 zDtm@ON;W3`X1^1W?@TEo%5%a3Qbh}lj)AME#Mn2mR`4^6)>R8ve4Aee#F(q#xCamE zOT#wLlBeS-z*C0D?awoWZ0W1MbWwu;%kX#KzeiCRcl=_|(|m0wTsI(m;*VZ2Ps{^% zYB>ff<2kx>7;9a2hMgwQj?BR(3#N?IK_m_FEIE5E{+5f0=+!ZB5LZ2m98b*{&j}QN zKE^~f#5H{i8l~%qaG2~Nrl7$cjvj);u3O}W2Yu$SkAyVFNi(rmXnPXC?=#yn(`@_v zxN7^H66}KaH1i$UtPgTk2R!HFq3MJ+Nz$T=h>|l=O|q?na?yc!N4FXs0UK0|j)M)J zm2DpVLzMN3!*toENh)RT$f^!unXOuf-_sqQZ@|Se3=* zS!{{LmRhU`9IE2>(=OTe>zha1iG0LOAt?HW8G)9Y$4}X+-?62*y812K(kF8AGUt>~ zQhjVr-pJe?OhGpB!uY}8nTmHu2-U#ZRUVJ0fIl#l(1b}^W6I&+yJ1i^VKQ(!9@_MC z`+p*vAbr)aJssf_hi#_Gxa?Y%x6uUmYuI+pomImcW?P5K2|k1Yn$uvGBYDWy34q_^ z2^aei)4WWUX=7fxG1N9qhWI>JqI?M)w!@)C+ERtG0}|lkVuyr66sPy zqQW-nZ~?JZyMp2ki)EnpRX8>-6_-+O3gh6Yu=N((Xt9HLAj)0sc;nvB_QT8XW49D< z+#1BJOuug|{xhjNR+qg`_V79ol%+{^Aj;_ucdno9wdBm?bl7_RKJH+5l&PdX z5M`bjdU9q{U2;0?VEsPsT$9adQr#_44nLOglm|~=oSY7Gs(zcs20Tkqr0{PRn5maZEYLjaK`xWIeB%R zWU8aj_C0nyxqs0&`@Nk05!YQ0hsjgNuGkAeCnk;8spDRDuWsXU>Np9VYA@G#$>6C@ z9qZYxxs2DTBgepf3E{j>^^#hx{OzP90&OuJs;_?t)CBgQk9ot+I0x?GwyT1 za4h#qkNo!!9fsj(yvj@ddmrJRVg~n&g|o|QYWV|j zjME))7SEVnUX3{2@XkBdbsX2It|KH}AHo#ENTCiFf($|m=A1j_VfB8VR##uP;rjf` z&#!v#{_R-Z-pTyk>{zlI-^g*04d7U0#0sLT}9zRxskE~-3{)wk29%DFI zxy@*felQHn63oCeG~oo+#NmK-rQINkdUUd7>X$0Jiuen#5zm-tXJJnwiwp>x-{82- z&dcN%bB!oo<-Q}oje%QkgbapTU3f~Dy6}{)fZTmn*e~&}u*br19uO_&BI2l4XtAVq zS}eo`byYKPCcVEz*@f@5MH7toQ3T^gO_Vgj{9e-J6u1>l=u$MH3pZ2azrr5Su7Egj z{%DIPSGP`+n#vhCAa7@y^w2apTGIslBWZFf%ByHXm!b(>iY5vpO%!(Ed@>7Z3~z-` zu4;=Wl@fGLbdXP_%IFwn8n1AgW01ogiEZ}9q=2G&^+qFN({U8e^uEan247Le)}ohGh)ndpbML`MR!L_SEjGWjPb8_IOkw%YFiE z7QGj2(g9U3tM)XwRn^j^s+O*RtWbsh4DSkKg(~c6i?Ko#c9M2^onB?H8uNtFI>+I4 z?l>jCGRKD>OPPZovU_6e1?nhUo>ldv)R=P^%{A{xJeg8RWguKiSZug-ac8Mix(vfC z!<#YO2N;2ey#);!hR28uOM;z@$L-HOTyxyaw!))ExBtK3Z;qRp&M^u8y!*m^+`J9p z6Nhi+iE&TCQ`0I#V!bGT7988D(EH-D@$|euAO@IHFC&$5uS%p#t6WOyurP{^xVZj> zC&xT*I~)($!SJ_fSneJv4>6B6G1X74Fgkgyhm79CMrZ3)Ml}zTJ+66}6YHa7sN-xz zQ$Oar%o`&r1>J>8L)U$#_A+8DMY%c6V+9%G^J{gnggIzKw#@OhyCJfE6B{D-k7NTJ4I7P7p0Ba~5mq+DVQ{NsX}Z+0 zG+hDlCH^byYwf}hNcjxbS-S$FpT!1QY?Q?~#U3WptFhQ(i&3?ozCjVQ*nJkGVkvzC zVvWUkI;XHGIG(PcSf*X6Isgd4QF0~Z(fD^D0d-CtPLdc^O}{$=sHWc+F4lN~{A_&F zuK;cgNG`(}j$qSglSbvrrq60%I>!GQWZzuK!f-tk{0rET>XC<2i0hDEV$XJsV3IlHZiZJ?X*oTp~gN@^$Ew?h=xF> zZJI{iYTGnFk3tF?Zh zL#@J54M>H{)h^k*oLLht9Gtq2Lu7wE-m|98@S!ohlQ?VQ4qr*atch{R@TB>|wm7+J zeie5h;|C`*q?oT7_8}LTN$!hCzV(HAa%sd?_`HqOuR12N4oITLB_}hR$giMSzSUjSBIQPCYePf{Nw)FxaFW zIv82ez;#8_r7D`Pfc$Ysh24sGg{{%9pcIEy*oPMTM7si_0yRh9pqQ;)2lHwJo)pKM z1C!)2jdAitS@*H)@{;6v1*rL4DoGxbPM6;O(L*Pu!;ahUd&8AZs;do5I^Ox|kd#g; zNgk7qcYb(&=l5-O8d%66j!A~IKzdIc{ zf>oHIe?~6rnA2iTt})% z_-|yEI2b5nkn{9=7aOKlBaYnH_cY?jba8S*jHr zE-x>+L10sJpK8WW5=>lo2z^xI>BVg)HNEikPB>Wb43n_Y?j1(%q{=<6R{SyJ_wq#v z<4EQ%8~hTemf#z=vyvip6-F=7ynmOdqOw-~LWj4vzSF~oYUQVU%94L-CvbBAzL8=G zQyA0Mtq;Y0iw3Ijy!D}{l)oB%jJ!}vvY(gy)gxvIGYsk>e?_&FeufXFZhS9?d$5F5RF}?31 zOiYJMmEH~T_#wg^qi4q?QL6NQfH1e}aH-NOfXB}f=5Y>kFdV&7rN^PRgC1^Er8gQL z`3O_S!48Jy@=A~O@q2{Xs>7v9Z!bLFMwmA_=)t6_500v}81$~-zz35my-o02hA`)= zO_7xR!t|EwFielei=R1Tybj@}ary+4ivO72jXI1Bh<~ZlyBXo;c2%KLrANBnhA_X- z;Zl{Cn_3Sd%xP-(NX`bl>Vx_FjSi!}?43W-??HrH$_j)@l|QEUunr>w;-6P}ncnXa zt}(1arAm+0`Uix0MTbjO-j(op6JcidKm?dn?So`{1z}orxK!zFgvXZ%vsN#)Z2PUo z;bzfbIpCxA}KMIfcPLb&*bQdpwVVJua zED#IXfEp}L*v@1ehT%G8rXJ(sH|Ejw?E#sy+ru=Kakkr&fAz!cA(6c9(40I_F^n5F z*c)nfM?J+J5@KqjGQe@y*|m4c5*TXmOOz#Gk7YKSE=7sEiq_J(=1sD$~cYK<51fK|4(hjwJ3b+t(f-}GxuSX z7^_`*pv{&Pcc9H(WcDh~E;9R+qw&aHWcCE?JLnxJM&xEMuV#D}*oo|h+Lz7vJDR4Sd+!xvDo_-%LS*XxLlH`^afk(G>dUTrNV8s7)GC| zOi8x9v9P_Fm2+kq5{u>aD7Df$Cng`;kvIAAu!}eOjX2&U^YKHiGM}jz(zz!dnhG!* z-)F*R{Zzu{*QVi7%tx1EKDq+(s&0kdjCY0oNxPKnn!-M^80QuWQw+m7tYyPF z6pHw^oI@sInq(4u*8AAYi%BlgOfpY1$z07O&Ew$2cyauONh9>g5bO3yRLn;{PPn4SUv-?Y|PEs3)duS%Jy zD`k?dlnZpFT#PcRN})?t3S9wl9sVoq2JH%n?H1c%u{dIn2HZNaO-GtY?7t%B;8uuT z=}m0Ud*E7Yb*}Zt{z(Y)BD&UV#XYOnLNjcfVepk5+LNZ}UX@g=D=DHYsjsf23z3?t zB)U{3(WNR$VXP#Dt=6uf_`SutqHU;fVeQ(lDdt&7z`HuT!H34IhZ3vvT6`w4?J$lX z4_6^HVI4;FL2plLPjJ?y&JoL|4ab zNMbtXu83ti=J{EYdRoBCsY^wi}VrrGZd*sP=Bn*F${QtU^UVn4b9 za$Tq}_7(~w`zegwc^6+s(DqlRf{Uy=oBQ`6MJTpzMJZx zeiWahjI&%X9t)d%i5^;0oi0Unx&q=3{8!jL+66VAFq{XpX0AZQM6ooJPtu`01s&Q$ z416hTK> zRW4nsa_LfAdzG3 z<6x8C=m;clf#)=D(WQ8cE~R~{uv_r1us>>7P&8R=hsByL#?q^}hiDgMoGo^%#q?dq z2l1!aC|MP64oqIT8xldb#S15t*DIG>{+07(zi$r$P$GsVUG9Fn|4fl4mArE6`QbFg@1yjT$xkYIWrk$A#(h#UE4f@jnGQGkJHkbiN?y73bQl{q zAtD{7NRvulx%G5d8o!T65~LJODtYDB)5$|jzmL*U3`dhnUb%HTv(v&)@F5*T=T!2_ ztbGI%ozr&jPNwrAGM!EMZ|c1*d1Y_;a*nco-z%SF#VvLb; zHgg6c3=%OxEQ0=B8xv-c0c@BbBq6Jlke8B>Pm+*)6x`nY7&dLo?PXQm^cPrb00z=Bd4^)n1=cP>pd z0WNdNGnJVk(+l+caYS`dsXfE@jF&jg@(g6Q+&w+xR{UNe{>{SVZjwo#tH5Z9a=WL zq^xM*=rhhL9d*u`XOw6b9olo)uo3|o`^bR7M!+6+n=^u`H0Vq-(G(%jgd#tFOY-^*HBx4XQ0LB-Nt(=ow` zwKPs>>GgTjwnBehDE89QU6r#gpW9fsy%FI*jg{_L`dN8(<^0Aa+m?P>S6Q==Y3z+n z*xtW>LB;%~pVw5@UcRAp4@xGM?yQ`*pr)~|aPWjsY{K5g(j7U=E<+a_s|!U=kJYs_ zE@{RcI+4Zc{;jdn-T50E>sn%UJ0kmX?y1||F}P%R(~kVe7ftVW3_gv(k#&uwyJMxz zzS6?{SDQZ0&AF$vB^O_gyd0d+5}B~KXAj{LQe*JB%FYjf_| zbx6~WVDPo3cMpk8*v-UtME)9ix^YaiZ$e@0#m3T>yd`@hYjW<{lGpTpPSe|Y!3~kp zy}@TAV+v!N{5u=#cI1^dGglisHhqxa^!JXzJ&`5N!IxrVS|YE;>JT+pT8MBHcIU6# zP};(hH_iQ?( z>Fq;0OlXcxXeplB9NYwIL|*c<8e&^ElwuD9N_0yKbMD!Y*YrV7hb6mXOPZUu{CinX{hHNISnhn-nTDSx@}bbp3IyT&mh5lJsX%V z;^8i%oJUJCZ;=$lJ6QK5T zxa&j5BaI%p_+X-kj~?0l_%3+KRKzVZP-9*0hliRExiBUgS+WPDLuHii@NWgx8mBhL zrtZ%FGk9co$EFYSBcBE9b~kP77}*)z8kyScTT++@BB5@UwB!a$TTt7mtETsIgIgl| zA`=ROOPc-9=IHjgfB(fwo_UFb4+hP+6{cFKe`JXnukL+%i*=+`YznzPmJRKPmio712 zx+m7+8ktCmm8iiV87B{RA~60bS< zXCxBaiuie`7}e-L%n$BCvx_Wg3H~)Q72gbkX`l7gHRrFD+1QnfECF5H^e&oNDELBT z3~5%E>l@RO--6HAp*oloWJuXiMc3XF3<&m8j=>MFp?vfNQ=U}(gK?c z-2oLa7ln~$g5X0?;#n}xn3mYHG7ImUT(nqP6#B*#v_^{pbgk&n{Oi!s$3D-05uJ&w znU8ZKFQaCHpGI1cJ{rjDk(XjivSVYmgPrlg(j5^Lv>>uBvbHe?eO&!6Tz*!#^s~Q# zYZ}i?kChhqpKe5Dzt&h&A~M(!95<#g_$9jb82YR)f^Wv2jn!?BZ1vT(XyyeS z-v=F?3Pm*rCxCz?<|fTpjS~uxIWkscf*&p8g|@IllSoM_vPl=PLP0=N zp(LcNRGkZ5p~wZ8iNthrQD}1^*{Z;)P*3LGgVJG_asMvL}y28kdk$tgE!6gM8rwa4;G<^`1>7r{OVP1-r zZjX)GhB4>>c$4Hp)EaB&XzPdv-;7{hIeFkYAv%|d*W(k2W`E&t~e{6B?% zn%->YX7YQRp2q}ea25=+E$b9WZ(J!p5c7SV#7bW;@q6EP z@p#(N8S@dAOi0sR67COKA#CIvg-`Sqx2L_9hI46ux;VsNDeCZ&c2Z7iRX0u9M4qW`Ql0B^G)9+zDfAz9Dh(;>Ay>K$2TuRd_#y_ z$)1;|k3z#M6UX^tII+6b2Yp7Q(J3t?dZY!!Amsn1v>fqExc>zAG5!u>fd32#V;myh zLRog=>3|$mBL97mw%Lh%P*UXTtj^-mw9Sb3QQD8wR^jK2wxDbuWmNm-Wd(4B>u_5M zAIQACgp@i!((wlWYUKM_e~Tw?_-E170EJAlR69pdn`EoqBUuB*f$>9fU8@pRAV z?VFo9TkOi5DK5?GCH|Oo0qQ}~i}86Xhl_}_v&B09-~6M~uE<>Oqd)0E|1Z(pp}U`v z1qqE?MMnCX^e4eQs!a6HlzE(rdR6%*_AsM}XEQS(t+5CVrocBf?IZtDq9*+)@dch( z#w0N!^C)y^aHhyB4bTE8=vFuq6m1Q!#c&*Imc{ri#s>`Zqda6vXG_#B7l1aKT zKcw5qlGb-+9)=F2KibO(>|syEvk0B@ZQ#d;#3LE=GjnDA9SZs|&LSD-2876fz+eVs zv3t22ZeIx3I}P_ON$Y7D+2Z`PMQPWFJ!x5@gTGo_?avZ1f0H;Dn~0OrcZ+jT-DCn& zxNY*3c^;}W1KApe--yqWjA{xxOcv`oArJ`dN|-7a!`5BsjoBr}_aHBJ(!BbrRP zZ@w=}EcJ~L8+^lM$6^}DxiX!C^h3p7aRU6V^u6jk-=85W{g;T%{{E7Pric2S+;Z=T z9A(J7ng%gTmhlCYpvu44e~tK;|5-4VDhmmwuFZKNEdxhohwJFGRk`ts)5VUkt*$@e2b zjZ9!?=WN20ImC5D4N zJBlBqT_iq5B^`$Tw736UvCN+@euHsiwSSBVr00v`^mK7b`UT=g=)->pcT;+!7?W{? zs78OfJY$S_JtJT2fjg8rO3X#OS&^A9ZqJ-6atF z|B)>Bj!a5PhQXHK_veaclqoI!FwqTpuTIYs%hQh#_rjf)kuE|gLobYZBQq9@%^5l3 z1C(Pp#=HwNbHqZFVSQ#-$?~Qt%#i8-F#8lS*!N6YzSx#_OUCJ%?&N@LWcdoRjuUmh zJAHn!-Zx)NN^2B;|7_5-3bZU2H>BSyrew?%Z)5bX&Ab{DA7_l{E7SjJR)+YE_%nK; z>wG8q)~4Oydl-HBkc=b6V;RSY?95r>yO}46K-P&eZ)W`XmyEk0>oQT1R__0yzf0CR zk|#{l`lCM$fOb3 z#8+r+m|(LRBC(t8_`qhP#-hsXM$B$1(%!Mnl+CB7q~$o|mSfZ~*`x-_GBjm>B*uxc z>DOVDK0WV9IUAc>In$Ypc9LB+=UHkpO5qaD%GriEgi(0~KP{I%+<&^e4HZcqGjlIW zwg@plvzsW*rWGp zr2QU4z_V%9Vkm|H&Q%OAtM4sJ_lq%N4qD_p;wPdW5(r=V-WBhrUE!ONo+aCm>AESm zCqy(W3;HQ1i@!q=pqm&DN>A}k7f<=RrM-u4e5e0%F)uwsEKa{%dCgGLWL_LM z=P8o)_Mu#?bQH@m?v+5BFdalv{Rp$Zo1elEWQHhWOC`2Ay9T4*9pZAaI_>8f^kL-?Yfx{OtN66`As1Gs8e<*EzjFG`c9F)qp+G2<(UHDKBz`Vy>HLuY*ic>| zlvd!Ga_-X0LTUM)UTI5j4EbeNJ?L{M*VG`Sxu{-80r*E6{}1AX`a~# z)E^egmZeK3W_=%>!z8cV@9qtyc@r~Z*^wbXb|Sp$y}l*XDMRNlDb2L{XF|DIDI(qy z>W~x4!gcEBpbJZ2r>y!lDPk=SbwZpJWL);LcdTW%IGIeYnq{@24p}-U9=@Ym$!Eqg z$Z&a)WmylWIV6=XqhXSFtcI>mtmK?D_?%KC@on0&Euk!w0z4LA;>jOf_PO^*mp$Tq zG&xqoo8GY+?s8&zWOYSrS#7|EU{)xY8A`)|=#|xmB`H2S#QUR^Y6$t4j}N6C8uClt zNTQE_`Pt}3K%9{OMDN6xM>rkz}(X@?%E=eqCEhyP*#oM7=*XlEkv8cGoSz38}D8qYj^sl@#)Hy|NSFQ|o zNY}YdN;7xmOg+FQ5$*7my;+2=xVbDWX9((_vkfVt{1vp2oio56V)Ev-=je0#7WYj; zB1uTUB&2^5G9U>Vh=rT`Tm2%KXgezM+!dxa409Vshk?Ca>Sb}3el#Anvr26mPO2Ed zeUr&bIdg{x4ELm`!RB=#S7{tjlu(+$V(V_H`qO3b2F(Y zY$~)I3wxA)$KWI1IoUiO`1fE#(lGi<*eAh$0(KwR+hIpwH^c4+dod=v{b6&XjqltO z;d>Ah$N{i9!5#$rNZ7=C==VYT{S^KF2<*Y|e_6k8(eFbrksSh@KNvv&srr2l>{Iam zrhe!C4d2Iu;HSanmOeJrq8Gv@&V3xd&(Z#K_4@+YrvtBsJrwqp+W%_(UJsk`m+SW+ z_ESpmegbTU@1x(p4|^EiAJOmJhvNI=`u$1$-WyDD2JmsP=|54w{|feSy#J4We^S5m z9AyM>9$CgTEG3P>Gnh4Gw6VLqR71qCnLQy7

~M=6YcY)LI^3BS`;NtGEVkHU|FGD57CRbTt-f)bb_K*W7OS_|Z!Pw)#Wq`P zi^cN6-7399wJRVZ78_`>@fN$lVzVrEiN$_uvD+>7u*H67u?-gcv&CMw*jpC+#A2UX z4EsDf&q3`9h@&lboW%xO>=cVlwpf|P7FevtVk;~bv)JtxyW3)$Ew;sC*c;IKOV=(O z$yn@Ei%qiF6pLMDF?QIj8E8CP>>i6fXR%Ed+itNP7Q-%x&P%p-1w>big)KJ7Vy9Yc zti{f^ScS!ATkKYg-C?l@EXICFm1CpDp0n5+7TadA7K`n+7|xhXIkYPv3N6;vVgoET z#9|{YcDBVXve?BIyT)Sm7UQM!s(svUu|si4sjwroD#eQJ1A6x9V7JJxY>nygxVp}Zsy2U=U*e4d-XEB^f%3K9R zzIFx0p%y#NV!bRj++t^1>;j8Tw%FAc`>w^Vx7dvqyUk*ES!|ufHdyR+i@jwrobhU! z2DK|7dRgpbi%qsznZ@q5*e@)$!D4^5*y|R1%VJ+yY@fxBfPNfaFgAA6u7Eh%ViAj- zYq9Ybn`N;}EOxua?zY&I7F%br%@*5YvG*+Yp~b$k*glKpWBRD_e5iH>#BmnuWwA>j zF~MW*pje}+;sNc#u{K=X zTE^9j+7%F+;NoOHC|=R7fV|wFbLgOW7Z_auaVn;}svITS6*!0r+f>tuHwUJ$&3Qfk z#Lz7>G16cn5~p|x2nu*q&7nFDjZ)ZFE(rjkT4PxmR3K_*&sCUFbnLEP@t=rX3Sp8< zsU8fwI9CON1q&2^FcTq?slp7z#oO`709>vak6^OR*^Mg}rsvniBS`w*cm!uU&s(Gy zzG(HeyrgSTs5+LaTAbX!KSbyq)24P-algLBGPt9i^_LU>^R%-#37~e?Vl*=vvVxa( zRtT+U1Hx?XA%ltMVSNkjtOpUj=HI5B)o#jJa-DHK^8Wv~cGfuyZXSI7MZd}WQ|^ch zW<9WbyAThcv8uXx>QQLGV2-{9olPNrQ+YSdmsM z^Hk1~{V#_o{(8tHOy1Z%{J*cAHSfRLS^w3}f+Clrg!NzTtp5kJv-Y9$YE?T6>X2<} zXEjSDnk4P4!bH8OLbrC7QHiwLSQqjmD_Y6iQ_psYDaXm-;HulhP_uQm;p;(G(apnr5oe6i781 zsi^Y0RHK0s4YfVB8cnkg3Ti3TXd;_Q#E?~^DRimPfSN(5(G*aPrckNTKr6P{QKNx| zU1>q08cl&!qk%@@ghD9NK#k_(Ae7pcgqTHLb5x^|%3wRB!i=LvgW888&5IG}ie^K< z2CACb(4tBIW?D4Mu*kzU1xC%4aB*)WQ(OlZcSJJ94RCQEBvaf37k580#m#VW z&m&XZ3K#b`ytQcVfNvPSOo;}9A#x9d<1)7QL|uaaF8I5(XyzyQpN10zw-yagv%*Nn zr2iB6t1l=mnnq+Y@p5M7iTg0Lhp}MNq|~BGsYEjm@ks@Wn2}~IlQRF2N;7w4j`k1o ze{-doJ2E?FEcP8_rJ2SIZ>5>%($0nep%Lcnj#VU$(0uH?>TOc3^o=Q=Lg17svpu)h+0F6>m>EL%OsJJDUhsjX8pc3a+G>JeC-CYzt;osw5-0JAr&1`{E5i?iKm{e2<%hIpRL9J=6-s_$rGVM(D}|Cq%Ur}x zlX*N-ORu|?OuA;y_18cHz+q4_-a?rlhv6J$ks**NSHGlqpvoc>(NBMzw%^Jk?*36J zi@cZKma@p5P_kIGCzPT^H#v5haaq;(9H@K7D_Kycm>q@s{W$TI&H>bN5BOE1&V=|M( zApffb@n0nfG9V1^&JVOMbiIcT%+{H-&F3)Cpqq-Wn^N8*tf%N1FbIWvxk!H?*z?F(;H33i+kdK@!>1 zmXAs)F%A`pR1)LMdxbIrp`#z?IA)cjrc6x@TE1{Z`r1SPs@aDEfze4NtaoSb8K zDautWW*bs!93!Wc8i&w{lp2Shlp3dW_&o?m>2OMoQyQF7<9z4hgzx+Y!&7RU@01$v z2Afjje5cen-zhcT9X91oj)u*Z-7&B!HGUjyN}uqZQsaE*sCxozN{vHmL`seKhE1vQ zlVMY8ydP{zjYBX+N{vHgMM{nHoeLknQ)(PDIVm*`nnH zSLrocY?Z}svDnWn)?~4#EcTMc{$jD67W=2gpkt!*45do_-9s#Pn8gNIY>36CTWqGq z?zh-O7W>#@+#6M8I~?4iXmyl!VSCPEXIN~y#b#QJmw%|Z+$&Y-J!G**E%vg-UbWb} z7ULBxDlYHGRq1uoE?m}Pv12VZz+yuzcDBXNvDn2Hn{Kgci!HL)^%lF)Vs}~W=N5a~ zV$WLaHH*Dzv5zgb%VM|;LzfN9L|xuK7VB#6KZGx*!UxvDhyx_8W`+!D3HZ>_v-h zw%CUj`@~}VEQXyTU5+EQD=4~KthdFAEjG+zr55`??0pM-RmHXboFqUv37iBXf}$QC zB38tNJOEz=LImYu00AF?5JP|fAt4VQRx}z=`TQC zD0Z@1a`$vXesi{B=PNc_v3ZK!t=JC~`<-IXD)yRUZz%SOVxKG4Q7yDPsfBh=#ri0g zquAMsja6*CVmByuvtmC|?5B!7t=R7r+oafQihZEihl*W}NiMN$p6Z1BrWBzrw!bWM zLVmLlA%2O%7G6%sZ}|gwv=q8Gb||2XeC_>zq;(IQXV3)7h%qevXoPN zPc6B2_~3cJz5JcrozGvE{Q7fp9>aHV??_KkXvSnU)?otuOYAoI{i}*6lonT&%<>v; zHnP*C73X^YGwB&G2MG%XorgiCWB-7V!ltRvog2_Z7ZC zWw3lf*X;0xA>j){e#;HP9>=v{xj09pvVYn1r-~DN2Vr#ICtM zZMM&NALcb8oL6*G0>}F(v>Q9GxMm5*`zWv*JFjR($%DqN6D#gayQ8VTnu3~jgHHNt zZ#<0QQ1M`30GjRi@5Up?Mgl;L;$$@w!>2ij9LY8YS55Y)JpL!*l&n}yMytnJ*@H3$ zN+)XnA96L(pe#A+>6*#YILs?gRZGCR5bh%bnICP)8{@q7TJ@?HI=O%o+=#F6@ zw#QPYPw}pIv8K2FAwE%kF5dKTyWB<=|KpnJbD>@w`#zVQe~bE;GIA7-Qe_W*?1L|8 zrhgfG=>A1T48JKLx>&BR6TZJ+459xC?xuSvT>1K+>~kY|QjYvx*bGlDZV^vZrnZDF zE#k}nwLbUt3zx3{|E16ErSLtWoJRxbZG%?sX(V2hef-u2+TP^Spfu^(2pr72jsuKNWPJIkZ%$ znu_l4;V;;)aV^+ioKO<1H(jh9-ko=o>~X*h`LPAMi>+`%m~~-!v`8y11R zd(a6T&g@epA4(9%kY@OBUNd}94X61UYKH|a;RO_fI%LQ0=}2B+Olf%m>lud^3<)n7 z@?&j>wXFg6uoLnd$eq~`IIgrwoU)Gnbx-_aOPfx(Lzf_4l(cyO_<0c=;xjBo4u*1- zLs8PE2ppPOIu99jh0Yv&t7v*jm)q+5A>QVB%55`Q_k+l_vu$Q1hu!z`*0vxx%IhBR znRjr-av0YRhZzzMGvqh7;=f?GJ0U+dhj+1^imgV-tn=aDsrZFg?DZz@IJf@0*O7H` zI&MU+sB@oTeK=n^9o;5zY;k#6P1%CdLokk&F_Kem8eUEzsXFEp!nuxVALnoi7F-Ue z7!pn~By~|R)Hn$Tr5k zrY4}Zhlq|Y++d^b#Yn&rq(xQ5ICZ?-CRcQ2?F=(yNKsyHQTpJ5QTYWIj3^kDt1WIw z@1a9;%~?4a>CW^uhCvu(XQyXke4R6>iLv*f0fS}hEIZrX*^a$yq3_`Px^=O}-pQ03 zUKeBRy#{saoCvz6#@_#8{r9+7WA96GpPMnh!gc`1f{Zn`-HaRWgXUMP!*CE|O^!vE zxh>mL#*U8yKLomJ))Y84m8QnF4>>fJ5dUK3ZwK&4KzA$pdb+0KV8mQ~k4|4U2_L6It&TTxOxmxczgF;2Y~$ORXU&W|)gpiKhr6_r&`c6G<) zcXciZ;dviB1|@9?vaPZ~WMC!tw9e#(D+ za!o;>b{!WKeAszm+I?tF7XQI(>6hR6*>QnE9UnjN$-Ads2#pO9VV|_AW%us+-PRwz z^wKLGURl4QK;}QbplHJUM`cyT%&Ow@;Eb}lrPaZ{iw5PKUU>K$fGw=9nO;^Q+kdrA zj5flel8SjV%4Qz@wqkC*DU7T)h0Ro{R@hw3Wy=vy@Eqxby3JRXv%{4&KCv5v9qEQ) zZcMsY)}Uh_HPVuux-tfM6Kk;%%~7*2yHUDF#XpToUn)Dt`%=d$axJeMcegXN{6=3o z$DrGx#v04IXg=_-Vcu{;XiD1T(2|s8e_q(Js!jdDV0F8q`i%##n6hrt!P@Sj+C)q& zPMC~I#Yyb1O#SoQmtPQ^RR8+H36l$!UyxED==y$v$!h|sZ8O(QEyAPyL79nPni-D& zeQk*ENgJl6__>a%6~V13HFZAjfuF=^*?e)<|?qp#yau*UimD$W8-3 zQ?7K(fVlA7Czpfw0@&V^^PFU^TzB7#BP*VBkqqUS)y;z&AIG*GF{MgYk3#+K4i&7sY5XlaoChAN;+G)B5zr+E-uR8Jv+Hf7UIcTwUm~FKu znQ*oX#a=f6KC)gn7Cv}UHx7Om_^cOrrjB_$3qM&K#gLp-!I0n9biuxG==`QVYMWpk zoRHsSD3+~Qp<>e%t5Ix`Vw|Ow_&7@|={~O5YQ?rGwp}rvgD%h3IHALt*?hvbBWa_1 z@P3Q%yCh=X&YkI@S~~*uK%CAdHQA1epk-cFT2*m0Grufvs#((f@EH;1#q=+LZ}a1n z-aYDd?2)1YjJd!^(c(9-u{tQ1H{^&qIvQ;4w*P&H4HTxFH z8_4N8K9=S1Cfni7w}1(67!uwvd270qb)Y`tR~ ze)U6G_{EU$iy^6@g0Y4Qwz?~VN7Q;3;KA_`b(gL| zKW97q;fmm7H zukQ-gGV|p?YJBFJqN#z@yp$_68R|DV__d{k=Zb7dn@jP3fDJ9e|I=+~1^#E+(4+V- zbd)rdN=xx`9ix9;Ob}Bb2>w+HMt2vk3E7DRKE@`AWTRu0ZIj2I+W_FlICx@>7 z!1m-i)dxfCBAuz-KiLN z8j$!NQ|uRtai;-!_795vT``VD<=HP3`?q2o9?7%ZX+Y?*6&tKrzG4?DHbt>w#rmNV zNqjtFT;e-&eYF<+9v2~pygl9phtuO7jxvvQKXJ+$o^?!@@55Ho+ahveA%nT7L(~X{ zI(3Q7Q+hmxq{m}OdOX3{;|X@`*2}D6rW&~;`%cWZhaxsle7WTcij!EU_VBaQaZXx? z`c52s-3@!ucpp1eH`|B$PTb{8u5gXa4@cPXz8#);4)vXQ?O#81b)(x;^fl=?_NdCtzv3{OK5#pA<_&`N+7g8oczj z=y)jq<9+;$)C(axZ2W`&-u$pr34f1|&1W{g#^u#XOD+NT#07255$lo0NWMc6{{B7R zK{^`usUJE>_>1_94if&3{x1jVq)+u_m4FL>H6P_5DN0lAAbv%-i;Fln^(Uf`SECS~ ztJ(M|N>|s#nH01O_j7l}ywaMo^3vkknps8ehpT397A+{PDx0xbX`236!NH}d^KN3z z(0Y{r7EtRjss*%-CQVvE9~R1oCTYB;6Fc+sMYDidXp zkXuv)Ue{KY)hsS5nN?ac2Vbo!=9HD@a^bt@mIaOftegSagK3!HxI@_|WMpRMh&=<> z2Bcd1gzcCU8tBxqSoR6rD5{Z*VV^J;+S5l7bh%BefahU{UT5hdR=`h1T(5&JgR%@x zRKVyJ@Z1#sC!oo2dJFU@G3^Pmfd3v!?5B<*%T^WZ`}JI;`)|;cod^Or>hMi{55Jg7 zu*b!Uj{zd(QJITIy8rh?@rJy;b;u5sr>yG z4Eq^q=JpUe7GbRX?L`D{fo2mlW4b*2V!iLVz~@41ewZ_Da7~p*AZY0O570YhnB8x}cMciZYXuF8L63@zWfBW93)t?-Hp#4Mpwl-iY zW&{#Q@qPSo;@Fj=k3a6Xp$iXw|61PFI9CZ>$a6i1u&>s&tC) zosVvR_ThU1-OqpH<pf(y#3Ym4Uwt7~du zEK@ijJ!4=Y_DU$Pod?ySa6w67O-04r>caAB1T(VwXQcNZkWHGhc_njerZmi;osF~-QFQ_sOLmZR1GlL?XxDYSzKg!-e&oyf3X+!`8r6MLs5)_S!?KzK2M>nw zQW}=sWCOw3reGXCZ8SWw6xRg}%j@7#i!~ujQNKPVG%79h?XKtSUeG=C#`DW=!F}F7 zWAotOGF;VXVZu4DRt3-5uwX!Fv*-RBa(`j>D%`K`GOj?3ZxCDk`sC1th9_(WCh*Hh z;Pm_zp*{G2U&9lObJ=UPZR)=WF6i*PAX3UaDCmqp=Vgm{_h41l!h~g?*YpqFc{Q#> z%ZUa~8E(wY3BH?#cldezTA!2q*UUL@R{b40+*I{`Xc^ya`Iv3v>er;;Q%-}uu3sDE z2OZ0W6$S36o)rblm#qM`YZ??pEW-Xwm*ID}Y6@f$Q# zp087(30)<};}2G+9hAbf#dz=umbmwABs`0Xl9La9q3WCYGQUkp(f@Ty=>03!aeN|Q zrZ|UpDt>9^XZYXSh9=c$k~t5alm zTr|D31`2)YbWGa0E3r!Kw-J6Tu?@w>)-lfggtQk~<1{C~&u|QxZtpMf-E01!-&FWo z;(QiM!$qPCnW=H%rKXrP(bQOaGFm@PQzPrV$9;uk3CGM4w798pVUs7Z&f;6J_2pWE zljBZyzAEA4E8H)!u>BOX7H1;pduk{VWafZ`@{_eP`aS_&CJfDJdfpoL%|9QSq zm;-;ntU;9F^HSDY=Jm86%Q!DcMyMZTffgPF7(#}l7p@yjf2C#&nj#>GDWHmsw_ zY&rXhvB@G3rB|!`1$3x6N z!CeUzZ;mj=65)%TOXRMMPPEp6=~$c{KB(tqOEkde2YZ6%DVsUBQvA){6SF}cYDGtL zGGm@aH(ln?N(J}_VKW_-N)GR0fAglrZuCWc;dI}GpA{_)-lRXicKUH~KdR1I_zgyt zr3uV`;dhne-wOXaC*0k1N}=R(UAVED>pDZggujG#G^x5sGYwxqQ*do3!ccM3421$I z5Uu?>3IsNOsrG9)OC8tz5=|0T6n;QWgDE7hgL=)%m72=J<0D-xZ&FiPP@Dkh;uK(K z(5%2Kv%tEz1xC>Qyb4131gvXyHzPXNQSMH|1qI=H2SicT)jtk_=^`&hA06-z}@!ZtuG0_Yr@_SP z)X)d${}=bXfe+FYv9#pNAd({KVnUPaXb1XLI<&kno2g;g4YCkAqPN z91(vO;=u_Ka@kvd1|AlFJoXGN;Ls;XI~_mQG2LnSdF#)AJN$XT;m?B(f1uks{9#D= z!;tVtF!Dz*YshMPM7xd2?YJX8bl)cbrrp2GE%9Ynbxg`Xyb> z!nXBG(t-=x{VvFtIw*5$`L|#~ub-Vz>l2!|A~fcf(3I~6PQhGWH_YWdgIP40Kl|9G z^!Lz|n~-5l-yN*Iquw)jcaJl7C$`p@tF!U;vhkiI@nT-?nVS;2Ma4L#>p8Df^@DPO z6gDjA#W}bQG6z?C$BD0C-Yx&Tm~>m7aI&jj1RJxAX5*MT%X~SOQ8xxE&eYk32=OWn z!*JQ1F%8@0yOU$}2xZ&5&*48sQJUeT0y~v7b0<(+%9Ue0J1q4kj8!o(guB((1(PRyKMp=2!hJJ9@qx9) zZi#j!M&jQ^d_C>+-}jy1OvZ>zxf=5Z**Kp%%RGspEj2i%^>0f{dv8wM_{=NzdMpO3 z#3bGDuwPW3WYDVgTa(A z?#aNsg60CZ0@9Zzw9?n9Y?q zWs*f`X->{K1ryqvfeAy{J&Kc8A|u1IV4S#+snioKQMNwEJc{$`j$Si&nLRtz61COm z+=k%loI%`YdcELB&Y00^+n6d7#JmD|$igRI_7OJAVEf4Yg!N@=UesNLR^C^z<){L* zn;4dQ3o6xzBr~sDQ~E};VN`6v=?Y*IJCr|e`tSQzQ}#a?!h z04m;59`Iw2gnu2`00mne3rV$&6yrC6O}OBLf3oTSVCLDGF#u}2l#q}XeU zeW2Kfip5%DaB7^J#_3MTZ_ZO}sAA(3o2Xc+Vr7agR&0r4w<&g~Vh<_y6UClV?6-=& zt=PMY?NRJA#g2=2-=muo!ZDMIaoLsdZ=7Ni6)RJ$T(RpETc+5ZihWP9pD6a2VmwY! z%8kbq${FO4R>L(g8~IG2ZZcE+^#Q{E)db1vnO#ir1tjlF6c!>_(NPHGI#do z6pc14pTkN*I6JMgD}p;qL-nos;Zm!u>ynZCCwSqJmJ#xgWjYN%4#3<}JU5<&~_D|iXl)KZ`<+~d=m-W&9@=y=-UPP~tn-LB?zG)sYY zA~xoXuBoL!tb=s1m+&OvPUEF6hgu30dkIg6sCb%M3PfFpsV2@j{ibOC1Z+IC+|EOY zuBoL!Y**y--5>nmj_7zOp5lG{6muLxbg~qv2&Qu771&wTI(IotSXR1-DE1_BkstNnyzqzm5S?Gs%5adjid^m>DT>_WAPI_a%uUB{(0FmUzd1%|%fNbrsjenMJrNa;8IRlUOv%oe5Pqrr~zPBA}QwWw0S_ zK9<_b>9qfLGY~VD8D;Z|=PHS31(BOkchyp}%Z;LlJ@a#J^3BDq)156Lwmo}G2<`ks zi>cLosKrr7KOu{UTyBKf+8CEbMeZzl^u4085>q7hx@?wQF=Y;K$#kU*#IGtXsd1%)d}?}0+mKV=W2`vpo@mU!BIt6PSaEc` z-)%SITe=u4j&29t9!G1U7mRV{<{}99GKk)H9leo#Q>+y(?2{_c;XL4UI?QUU_%1~| zehf5iP5=QM$z#Pw8U7Jy9`0_*tUQku-*(9HE+-lDc~7CEOpg^GW%(Va8nYQcx~B3s z68U=zG(Ayfbd>E!u>uGEvzc#XuA|j=f^+M=ejQ>9J?hOozgc;6cpHx%<;t7rl`)^9 z&ZPLFSLARVZi+8@#SACMvEnCcrOr-^&$%l8$2x ze09v1dbrCfqIYUNy5$Oj_9Z|^$LM3e!p1Im!FIFXESkY`BOdE4 z=R99o36`XLmkFgi%Y?9ACEea@c2&zUUXv4R(aau*NN8`Esu`V{2{npC!B{J1DuK7U zj-V2*f93Qm&7N;o%)r+7n-w#tX~$~C%xSi!UyA>na+DP_oUBeW6QGauvLSxt;q-^B zn4v~4D`tAz5Le6y#uYQv|IZ z>RmCzHN%l7Iq{hcM8Fj@2UFabq9@9AxN4`Dk-87&>YUxCMgKSJW5^G3gLBZzMJ&(= z&+%JR{cqOCe6v1A+Svcb^)XqPAEre?273HD__Q!cN0|Qqt@SZtjIh}ir|>CfSHS1w z&w2-ku&CqY4f+MULgr-nkKnoo{HNgegufO(`j@)x@G(DQSIFSwVqFU4{2B1MLWb98 z!iT-CT_H07K398Sg37Lt$%g-!bIlbp198n2GK1j13V$$sPGMuh$gYq%A3j&eU~=BB zkjaJ56*9=H{fHJsUgRShLt@p)kRMh-m;%Eui67o<$ZuCA3-*v=zi>iH<_X3ApxDcb zy{*{0iXBue9(fMp%5MTrD9LnIjGx_jH_4DkLdVZ;f}Nun*AxlHPjNywQ?WUUg%rD0 zu^%e-fMU-own4FX6yyG1lEx>BeXbbSCrMs9Iw8L~S+Smq`KL|6kDL!O2zI{?7tQJkz&78>`BEoDE5M4Zz=YUVxKGarDA?)D9-yjA-u0*Jrz4& zv0;i$QtWcY<|$UC*!7Ctpx9lC-L2Tuiv3QpzbN*;V)0OZB+u=fkl&o5STDsg6&tA7 zD8(*TtVppE#g-~|lVT4;dy{k@bwWqJLWc3gHn!lTHXZd>x)<=?_%q0coh9Yj6X!%2 zdGZ<3K<=0`A@9XS>yQyv6=7=$QCPoO4+ASbu-EG0-C>F6ax%iNYwh(gk%ks5Pxe*( z$c;Y1x(gxuS;iN^?*xAgeDpUkjFr_equ{grdCd3?IJ&n;BYd--5C?Jjv`lVFeH z8brF)o>a6_5903sZQFc1dWQDowaw>9+8setBcQ-=onyto%j;Uczy5#3HlGT{RyW`9 zDQBo)P>R0f;FF;^u#!xHj{z%Xu(iye2EPo~#qbxxzY_iu_}9Y^!JiKQcKEa4uZ2Gc zKI5DV{}uQZ@c#_I68?MetKg%~S<8KDTfC-ael7g-;Dg21GJi4r66czh`QOGhE%UF2 zPs@B->{CuMA1sO<_=#mcLvkPhLw>t8ykMU@bbiBSy@IuMLKyfc)>E-zid~@Cc*S@$ zKo6S+7xOZdWU3UqMzQM^;{x9vmhNuFo>6R#Vp|m3su-sTde~><y9mRgE*dvO)sMsrt{YA0&6^lpjD|u<> zg#6}s#ZFXgh+=t)O;+p*#VQo5R;*sJ8x`ZGR+8@b72BfNR>gKIwo9?E6f@|{8H?W} zwsGT2c0xyQna`MG4;IhG9XhsSy2!yI>r-xoj=^V;aci01znQ^e*#0j3#o-$}d~z9z zS<6R6)^_XaAps`?0On z+v85Wk5-O(j0CPJD}2^PMAd|~I#Y=E(e&#$gy_Tyzopjd907`REw;~h0plXmqL8Ig z$d4VQtv>ZT2MODzzvUodyK~lNy0DG=aeP(l+|>I;AtR!Y(kO(rxp6#P!{@pQ{&f)2b#xw^1&zqe$VXYnRN!+&zTa)W&?dV&L2f2D*EUqIt0^2B_2;so7Y_vVM zj^0EYr$S`sWCX+RP&V2*nb~5ZZEdu>SQ~9_x^j+F?6GXLxye)`7sE!IcHF;;pv!H- zM*CW{Xs@$$5jNVCt^Weu3G80rSTSSSK<~nh-k?cwBxC?|v236j&5t6aXsq}+I(Zay zODTNdnAN7@d(xq?g!mULzAeC?0o@9}P&E}_C)|D(G+P|HrrtLVH{JowClqRM?eJ?V ze}mY?dR$ZaJ0EnNItXD?`6K^^J2Y;TvEn2DE&^T8j?Kr%^1TE!)ec=#@4Fi}mVl-_ zMdE9&eB+@IwRdK#nu?F*(HS&A7gRM{>HwPZ7i1ugkXn=*{Zw7b6y3#4!-oew>2_7FUXI)6loNSIkTNcbkdr z{xtaRt^4GJgJ*G%cGgE?%p7TNTNnvo`~4%{)4jAz3^H3{p@~=6gC8XjZ6W)iDqyVk zAG3wTHw)Q9?_h1(!P*q;p%-3<-F3=3+H&>7FZO7UZI{j+?KL1w(a#s+OJ0T2%!wH7 z@fp&bgkN862T?Q1(99a|x=f9Y@rsMJ);c^E42yT6qxf@YW3kT)w@7to9mA3_JaKE2 zhL~xsQ{>(C(m81R-Obnc6))-tLbtrg|K1KK&%_9f*ZtwMOwNK&rexzMBQl0$M8=RG zr<%&$B#z=No!|UivBwqT9Gg7*7scXHBLr*bg#6|V#m-WUGf+aeMzNM33SEfw=-hfZ z6XCpwdg!PVwqFm+%xal@^`RAtN>Ey6CIvsAuK#+ zNO;bW-#m=}f<5Yl4rlYdNPd(cj!3glH=oQ;Pi>dc{5YJg_C7&ehvEhFmO7A8AX;8P zMY8n|_0i!4L&6J&{N_RY7mQpH3}P(CvF!tKKeps@J9O3%x=6|O0I>5SY7C!YDMB)s zZz+eOB$sU*6pm=3w68;?$@X?!K3|wn3w} zEgWNG+ThvkkJ-Wp;3u_>A>lAXe$L9+yGh(V!G`>1hhjSwJMtEJs2bQu`5RpWb#-s^ z+=|H`x0ZYP1F2YtS298Pto=RUlRvDv!XJi&KMY9?6pS@cu$CXo9@!d85y#Moy5{DS z`RUaRFFXsQTfmLjTVEmxTd#XF00*VLj($gnA5hmUKhQHc{9s72_32DHhkFQ;4)V;xjB(c4DV1%c7enNAbwBt6hY(h6Fq)&f7TM50_%wejEtc zXvM|SE}U<@vcDOtk(V?D7spDw;F;>p*8#8mIO)bTFoIe$u=KVhKZQ2g!Gk}RuV@Np9kO(!wDAWX79Yk>5vEW7TW_S@k)3tSY zfu!p29*{M{3p8R|3p0TUFBlSDFeJPXjJyzRkuzWC?qG2YXZbmY*4Q1{EI*qhquO+O zalM41_uApSS-?pw!LX`$k8x(z3LoPfdv6=gJjMIA;y<6JYigF?t*Eh&gNEjZc(&lb z8&6ZS{M2&zUd_q}58*+cF&=1)_5?KEFrsWu+Y zgSq9^+_Br_Pp7!Od!x&}bJTmuvD@BqM^izb-S>)JUhE4SmsgsW97TpW_shg-E?`{b zVh0I-&zS8X;hlAEbdY3y>c1VNlOoaIPTq8A(v;>?2MK?1>EshA{C%ajgQVzFToNFT zdG7C-$?F0*-p3N5TmNW>9R?KQMmtZDCeHBNN>SuwlO7bU!sO5-MOJZ%rqcmg^evBe z7=2UK=;&MF&M5jGlA8$yD*8rPYDeE|G>DG69V0S%*Q(-q(<{pDspLgh*3K|Ph7{%H z7NrjxmOD0Y*w|5d7mmn{l*&VT4;`AzGqMM!XN5n81T(S*4<0-a{|9NB^)=)cr@YmR@il}}@i$5!0sECh_B^}9y>&GLw`*++ z(;-twGAq0aF;pI_S>YL_MKh}0VyQ+EEgrC_6=sInL|qQ-L71%P3~3L@D~gj?tHt{Q zKh~?okKM<7R*uH5CEYxEf%-ityV2LaL)Gsbx8jHEce_@o-7XB3sq!`JJYR;bpdsd|0N|Jr)ZO3~OIM!g<9Xs{!R=^a{byR9HxuajD# zUQ-KgX}#v+Kd(EAdd=yRdB>_=m(*4*C>@ZUoiP|z39Tcwo2uI#EN*{m3i zUCZnCz>LgBI!ShVX6E4ZoI&ZH3eP(4=p-4i=#aL+y4}%QXxw$S3`d!TSUSmYR|$3V z7(*vX$FQgxbPsUA1;7{ON3XP*{&X-vtP&~=oSI*hDpWS z@T24CLcXLo`ao_w{+B`XM~6=Gm%he3cIETKF--hBXwKwd1rA?T!~(*zpDgioL~t4g zE0d4s6$knbT}1w1Uv8cQO|Pz`^5!qRKP~a~h_47Vy-wtnEQ^U{c|l9p0*Fgq6LEmYO;V#UYpKbAw|`Q5jKj$$X4CBma9vyGss$r8GIo%m3-jzpLI5gx}u z!FH_E>g{%s$fKͻ!I;>y{WeLFYR1UYo)xtLEC!$`yN$CQ;+Ra95Zs0sERe|qrZ z${I|VT~#)3W-za!ys~U=X%+HGz434Ooo_m%J_Z>i&K-S~6wfWLDzBYeQ{)kaHtC|W z^2)iT<)!m*c4=9~Jj|LUrrwG-cAm60Z&A<8;F%7I_FRavc{Mp%MK$)i28rT2a{#VS z$Nf7F70=AlqRLEsWl6MIZZ@+K*^IE7$hvp+M-RSs@vZmG&VKCNk>k-GD4)l1HsvU- zCX{o9VJ;L}&J{K)L9wB5ckMbXvj`er9La;a<5f=Uoj9*iA@WSSomNikoj2c1|7-cO^|b{I^ZU?d|8^NLLxr7eA&5CSfe~S+0;nu*N>FvY+O!~JIN*|DpI;J*ti=f8zV_4 z+g^S!cM)$>zdqNANfUB8EAQpNPTJAA2(#FECpVYEHHjqrw3MQo4f}?C_eN=XxRPA| zkuT72Aq!qv=Hw4RM8SkJ#}`F0xXIp9aPSG%ESnt8#j9VRmH9Fc#|s~ghtYyHD`{(u z3o~$)#?!V<4;w1L|5I(~GW@4joW{kQ&cb>QBjoNc5b9^|KC7X35IW6bpJ>RS5%jUx z@fylNsISGSrb}odLZ@4dOC%(8HA3?23WOwPF7lKoxMz}J8xfKx{)~`VHtbaFD}*E# zE{~LF&(sk2>5=!iLPOm6pL%|p9jeI_*8}Tmu{#ht%Z6+#--Y1)_(>~A3s1C%6Y@ah zorEKrHd=h6`s~(Ssp%+9`w;8JBpb42*q3EERj&U!WnH)gdmsTR!668pfnOR9{S(8i zG&2n$$#W$_l4k_eF&_Ea&d+V(@9s;L0%x(}Z7Il-9c(uI?)W9($1&a25%;rjqm8{Q zrm0s&+^@rZ@5TtV5%>SXh@I3Z4ojm zT+X`BNk4YJ9Rpzj^Z*phaC-(Dt!Ozg!sxQRGQ+~GHAxCD%CsQ6g)n%PfD|B&B1pHi z6vE7;oKsh7v26}k%cRVen(>G1^*=Bh!WZ%JG&DFI0H+zaN;3O+<6KEr*`@KkMGn#M zfuy3^#>?r0r4|X;-5Dj#>V?I^FU|%?GD&gQz*g^MT(d3=!*3{l`A+ya)B^qraLr$y z^ScN>f1{lrao#6JpLiEMN1yjxdN;nY4mJXQcUTXzCAcnJZq2RupO3nnluBCe!63)$ zv4nY533D$wUXR6!lIGETEK*+DGUk02r@fzP$yt!RM7i3N{KDkvHYt`KOS9BcvnVX} z0DH+ouyJJ=YoaGcX(K&v#kNI9iFvMr|H_y;wzp^Dr^9~^{$ThU;GYlwdHAE?Z-jpd z{6D~-0{;d0mGEDLe=Yn?@L8I#z+VY}GyLzse+~W<@Lz|IIL#m7zX$&f_@Bdn6Mh2n zvK2m;<^KtOHhe78tK&laKf}Ka{x1|64*1}U`78Vr;C}$02irmL)^QiNzr!zr{}Fs1U$+bXLiqoHPg%4ZK1-T% zRW=`BNH!l}$Zz;If_>?P{H85Z7R>L2{DxZ~2*&r7XW3T@#&;HMhGMf7qv5~MamxXr zI|aEDtd|q=8*T?6Sf*lp8^OM<826wP>~6)l*j+FK@yL+q+n*sc96#4lUjUc%Q|@ep z+2rw%^{;^Mz0Za9a#wWxTD-xS2=!$o9ZSyre5YeSH`<2KWBFuhc_Mu3g-P)H!%v2v2_Fl->+;}tgnv2w0DP7k z3_xs4q2AHX#>`L>xATCUVr}}36G}3_R}6B)-c6#UaOn0a_AkY_NruF?%?a6U7wUIi zazAK9QR7kG%kv+FzLw0>yeCZ-#cR^?{4GupAyuolK*@g8IZoSZWc@N<_UhE_5bXf` z+FCui4?=0yIG(yi8h7?|^vMel>T9t{_%9k6%aiS9DSob-iU1{PvIDT)Py&;db!#|& z-uthjWhU9XqII1calbn%l~?N;7;%5GZFiE|9^CsA_;yZ2yJMc1hl}uI-4u6S>GXxg zRnx1BYATA#E9TYA#Q7Fgi}BLv>5*Hk_)+ju?eW=sSq+<0u~HGk^>|mGaZaQf$6r>>nh)Wr{T@#<7V!TjzuvIdCq{ zJ)JOVa%fRXs30Mf7`ikuRGA#gO>4;C(XeD!Xi0Lzn9U6nUuu}LF*KrUL;m*Ai0%zI z^L|9IA%AOVMDNg&#D@GWI9zq#)`r^knSov#8^)xBUI@JzTCzR!qJ+%L6MJpUtV-^+ zHS?;jy>>T@`Ks6c(3oAB7o~u3%Kp%l9hsM>_1fAnW_M^zVnglTQ0=zNs_vnQTYK%! z92X3Y+0tus!<3znPnn~7_u7bLGU7w|UuEPag!1=il)gSk=H%+Y(`!%v^FEJcW4SoQZn;5XD->^z~?jbU&=&66Sp?lh%)mxHrTi_ z^Vc`n=rZ$nH895H(3G8-$m5tT4U4)KHB@$=+Hh%FLqV`%WbZ3N7=5yuN6IVeCae=~ z^`^XHn6!TUX#efK{{XN!dzUo@qxXpW{{-f9vZCKKcM~Tc6 zpFJNw^?7mE!Gfy9jxVSPh=}45^+QuTfnbFtO0(B|gjy^*40}zX^{BlbqM~Gkz3!r- zgzqb^@mNvPnF%^M8@;_H8thAh_Q$jtH?&H)K^ixE5zflELNb<=<2%%X%I6HzD6z)y zF<9uh&yfe>e29CPl^b$>8F=pw$Y!S7gvkVE#+Y17ycyDiQ!7xlaF(1BOD>t(`Sxa8 zOS~1tL+!QCOFY=dOyc48W_wFaNk#Et%zke+gx6HaPOvw}S>p8|9&fLAdx$Y&BJ&tC z6cD(0d(HgM;3XtIUwA(rzTRH1@jN^;!xFQU`O?OWvcxZexSzf5;(3Qf^1>v($KIUb ziD{9rj@e+nb+f@(FR|C{Y|NC`oKxdCBFxG~IW`;Ym!|Qaxx;%i+umf%uiBe!Yz^WI zF0XFSG>=wnf8h`k;zT6#Y0XWJ{x}NxTcf!Y^kEd=B zbo%<<@Yz10^VhM2Agk)geCP>vFDR!S?4=VP!VyhKfuh>S#-c{_citSPCGsU=rzPxWICnS663)WMybChm~ zVxtthSg~1(@t|qp0gvdF_^9~_cBf+BQ|uwdexleDian*+Yl^+0*n5h7px8mhxN)JR z%Mq94C8$_G#nKf!SFv2hIOi?TPEl-uVpl1~9rT6nX2rOJzFvG~ni#r7+fkl?0~=!E>HhhnEHmZ4a-Vq+B>uh>+@u2gKEVpWQT6uVWi?<@90 z#a1i!jA9!Vdr7gsD)x89K2z)q#o9o-6rQ$sLVnXzu|A3oQ7lifixr!oSdn5Sie0T( zonl)R+ol-4Io0nf!0bixQ^WAJYtrP|CX|=3@9(oaH{|aPeG(j#P9oX?HAp~9jx8jkpETa zEs93tLkLliN$&iXeWqc`W_j!lJhmH;?GFu2#B&F_#UuDuL;h}iJ2W(<^E;v1UDs`3 z9QAL4_&_(19qbmrp`mt7sCIkjHyiSIhL-FI4eff}^CYrw)G%>lJ!9V24KX6GOP&e6 z5dXYHxnx`CO&pHpC(8q&+AR)kC^slsc)nrDmWKS~&ToYBH-~D!3N6`fGZ0t58F6kn zVeS4C?4xlF`J3xsH=+EEfk*#x!rFhGfVaZ9=el*shtRGgZ9_iBU)%ZGal$1*lGlE5 zf(0>7#2BvrHN?I7gwVvV5Nl||+U+Ntu^D5vwcER$vAZEPG;w$6`S{ws7H*i2QQR8d z+21fOF*I>!XkGl0U2jASmALi}+%giW#WfzdF;9G!A8Gkhcu8<$yZgJy)v zt&Af!c-b_-M&!Qj_v}MS7GtjHp0J6YXfwj{V1oDahWWL547F4e^%?5r4_bVABuk|% z+(Zu82phAM+MbN`{f$^kO^l$p|(kCtGRVk|6~K)6jK=D6-O z=EV5pJP~n5HqVacd20>-VNTOqB{$p1Pu90#1-opfpXGgzQsC47U*DQ0Ux}a|IBk(I{ACl$2>ce#heK4*PL*EW{RcV z;%$M0Z1&w(l_8(BKsRT}R(SQWiMssdu!zIRd7g$rNqCyY{oVvPQy;EoeN_^MbBb{o zTnEkRYUFf;#XgMW*`P+ReuGWzM95n{98QFT45>X*2oy;7TiO-gx|`GJ)py$zY55_N zjhB1vLtSm69IlhEpYaAJYHswrIz?)Nr9Cq;#~GN)3fJpJ_Td~Kj!8q~J>C|WD+_M3 z_sDz6HD|8wu-Ls`eo6=77S2aD)o{TiPa)M!&PB5@vok4pLD~ec8tnf*XhH@;#`mI!17W%mt8WjED06SxWm^o>& z)y*7y>I`&zx0h@PsT)&A9i{?4Yxh$4oLsm8{yp$-gue=Y1AOXzH^XN`y#+pt7;`*! zGT>JDr+_aj;Ir1>4xhpolQDH;;iJ#0V>?Bhb(EJsgiks70DPJqJP4ly<{!a-AO6Ge z_rU)Fd>``tQ}{vnkHV+U^B8>c`%L^~l7S(aWMIf|w&TBGJDd;(YKrYwtSeFxI<{(g zwy$FB%mo{y*tv?0R;)m=LdB*jwnVY(6yw`Vx_2t}q+;v^CEXVk+oafgihZEimx{6L zmS;JkAZf6z3r3R$!D!MTSe{}d6r-u1(9xVj=qePeR;*sJ8x?y{v4<5~t=Kb)y`hiMF^Y{-tXQ#9#jaP3QwH+BJakWZz$pX4eyZ3i z#a>bDb;aIS>~D&3DnQ~(c0zs=RIImRS&9u(Y`9`06)RP&OtHm^Em3T_Vz(*A)0HGI zzf|m5#WpDRhGK6i_D{t=Q7jIFJ&CWa6M~Yc7>9zwzjGAhRDfWd0FY-n0U+2+#pWpX zZN<1Vv(VkA*n^5auGnhD{-oI3itSPCGsW7pb@S5R3HePQ#lEH3*@~U7*jUBJD>g&1 z*^1q$SV*z&EA~Uhex}&36x*WMR>gKHwp%fXMTe&eP6!iFik+%hwqk=7yHK$)iWMtX zs@M&R-K^MuEA}JBo>c5<#okox&x(Dd*vE=-zig=+X->#*dMnmfu`P;iRqWVpjleak z5KkW0l4Z8u9c<8WutN(?340*);{zAH$yot$yhoQ{f*4eJpF%aoQ;YB)1#R|c-TCYA zQ+8wuc?{g*s6j5FTH6|6~? zf~hl)-aNOrG*j`PX>1(z;d;rlH!aQ|#QV5%m0Ad0`>1%BLcDL7!=zPDe``l{Jk$x| zeXRS{j07$zDxMBN<9*bI7}d}GvwjmDPe)6`m8$n5MAyN_!_ZRxvo7fHlb>D0xky;= za*+cr2}%b^!}W09#3(X63Mq?1{woUM0mvRoatJysHm(lW32Tj7q~<6Lh37YmVw=_F78T*NjM}QQn#DyWvr0?m6qQs|%qc6) z%|dxCt=imN=U-Ak*g=2hT2)}H<&LGQya#rM#6W{iJ4;U91R_JKYJ@4n-v2aK6$ z@iSMR``hc?*9_hJ)(2ml|8Td*KYpd>4^jS~f}VqJu4b>S zs+d_-TppZ(mH*YjzKaIsoL;!F4BLe*tPaj8tEn!`NG~j#S2DMDdMSea)B9(nV{L2y z^upSbs+vN|8u&c-2hy~ty8o=!i*q4Pe!;c`tr4Zh)OfXN8fGl0!o=DU>r~*!dS&Uc zQ~TIR8@raMedGn?OxA$(u$T!R>inCmY^>?GF1))+I@A&}kS>;-86KIv7;=WAZ;sy2 zqM8QB%rzxvCOb5i(4~vmm4w>V>!922&@v0LcKzUt%U;lMtU^cfSi6W+0Y4e~+X||m zaBQ5h;@gHBcY|gD)l0YlezD@CCYKEL@&u}wa81QG4L5p&W~rmd(u)-zv+tg1!}#c8 z<`4LOM6!h{DO^+U%lO)oi5?d#z8$!q47%M8t;Xlk^BD!plV{rW;furZeRECv8dRkt z=^v=t&OcVWt9W|)a945k9mF2w`9A!Pc9)eCO>*iZkY(Z`_BJ_^{ZJx0AWlbi#g9dV z{^Z9Q*FH1$*1+zxhXXVBygFU_laqM!SnQ4xoA>{j4N_!pheo?G^sg$OP+DA7GAno< zwp}Tc^J}Ksi)y*xVK(Ol!JS4s9dtr@y#%ZWeo0(CXG3B)*4twITFFq;yB}2G?y>Hp zo@e{DE_2N~%1madtsNmV>*0mQ#9bF5Cb*c+x&-`ZrLV)UFk+{E_Zfh2yPX9?cDcg+2$)GY9|%j!v8p_T@aFpU$;;N%w5{KGaO#wGfs~Gc zlu0R5X9PZaHPH9j8G-7pi3o2Fq}XtRCmiPq`xu@PxMp+U$u%R_?oX`W?%TIj%==j` z;ZhpT3^ zw=$;Sx^SA_Z)HKiu@>bq23ZW;(F{&yp6OPhHoG;hKp^|yjFR)lGvB%r3eM!mo62z6WV#@f}05_>LhtQAn`I9Xh|=SVgdx6x;2DlI+(f zd6wUtgpS{w1f#`)V2c#HMX?o%!MN>yL}@~~2~!SkCm(y`7p{rCa-E|B=-8AskzC+Y zlox-)Z$v~*<1?h8-?L>kEqc)?Kh7R))oNbUxc1vYyh~)2VI^@Z;m@5)Vh3hkx#aSO zyy%A?-Ki*jzIz||)c;O{&xm+UpLQrBmlzVc#E_rgH=R> zZw<>OKDK;$c6AVs=rSU2nYP6ZuVek9bIWut!XqQf)P071PRDQ`(Ck)jGN;viA-JtC zof&YPn-=-#=KBorkGH|+I_BX_ho9XM7Jf1${A9>)7ZC~eb6g8{Y!Zw5HL$#i%_`zGNHL&6(|{D$&Iu+>h;8QS2g2Yzjj;mHpiJ+h{S zT}uYQ-md|CI^IXEfLhPux0a(@LbbqxwBKmIdB*VM@mELlE%)@zTP6&(+I zfOsEAiqh|qH;mDnANFeTSYRekUwH3}5R#GkVb2@yn+BLtfv%~OAKcm>`$Pghjr`!h z`(B4S`5|^ZcHCWsO4Y~V@sZ96y@XQXoRHTwH77Kr zaq~BpE@DoI?d3P1Tkp`aR>YdqxEeP$f#xEo*|2@YnsZ@%t3k8Yp=&C>k+|_9XgWKp zDxZrLAEPM`tFyR@oxd%>t3fw{5y7$5HWlAu&|K@#HI=`uc)kHN#g4#kF238tLY+y+ zR9~w5tnoatA_?jaTV|~J zdGvnAeC`87m??ipI<`Ggw+pYk=uOyhPGiz>atOG0^wJ*9Y+!^|$7e`Gzhfu-vo3m^ z3^mF-I6nH(N=paA?rEAF#5b>8H#frJy%fBf42nIQ(Rj5@mw#SO93^i@I2fGOu?nQY z=g6ifexhwMB-$oJetYt$V9Omkzxjm|O0q}a3EiI*dt2#7qlDyH+D8gqqr#^e+kD}> zQaZBmDf-TBrtkyJ6#lUpuev46LGzK9Y^)(wtb#xWeXB2p)JTB;ENO_LsF0o z`OSafzhEn!kl%29uwYLs#>ol6I61-4;T+{V74&qhT$DM*_(dL6>-6Hb`6r@AiqkU( zJ)i#<*OXQtf|*TJem4zo``0`*75;*BtK>%j^+-)Zr>a~yrY2@aO4xD1>h6u*k&VbHWEj=Bk8@EP3`LK~sjs_gWK$#Z z=HrnOIrVf`s5LbrcZ((V2$)YdKHIOk5jo!`_F02`o5p7!9?giHoe~8LUG#{Y)hW*2 zV^1i~Me?2N@c7$pBH>Z{5{D){vcKCw!sGZ~I*5$gy(a?77~L(s^Rl}wGEQ#nW|j6i z(!|+W;i4!t+_O<^i$>Ma5i~in_cq`d35VrfjGJO17L}NL6yNCFi^q%@Hga^{#kt|u z=$^qhaA3xOVAvgM^qrNSo+YQ0(IO+so_F)Y_pFex+>15(j%uATEHYL=+Ww1G)Z>~O zeTO1Og|SB8e}Dqg&Mjys&RC=GLiB^1p?>$n=Qz3s3^EOL{ zE;)95+&gv*?9}|mq<^$^@&xqkDc`ybSMMdQq1GuMCVA64jFM}4GsSy2Kvb$I8$qKV{!9jR0erxapJ7QY)jk0*Oh2Re@9&I5=9V5l}S@%=Sl&-7$y?oN#%cq`q@_1M( zB7qd&j=QolCNJ*ur>DCmzp*xOBkJKh7SA1e#;ofuT6MxZUp%mD@aOGsGG;LPixl5G zAKm`!!}kQbpZ~_opS`|#6MByo7GJq+!v3eb-LfM6$)fv{=A8GMv3uuoKuuQxF|Y!D z34ZY?u#xcpjNhmD{hGZLW;Kq^N>R=Kjyk5V&EB!5qGE1!VR`l9>YS{?S=fiOu$;#> z6;@Z36zcgD5m!#U`7@!M*9!QCXH)Hx~RMyO#sH7V%zCbAI`hFQB_w=FRLv_ z{U}>dTvN*T8&HH3q%sGzdenTu3Ma=$R~^f-7@?vB89dT6i5fk4Nd}L5S`;=v$_Ucp zNKBA`_XdH-9w{R@$l4>}8JH*WA8+buEqdaP9@a9rH4ep*(_vci92<>FbKZ)l*fbNl zvL$?k&5@R3IOnZ#RFHG*kQr)F{|gtpc1O03_pyMBGb#L%3ChPk~HxcSnhp;3vU2`Sumr`@Ez>Tr3CtJ45Um?+>VRl;EX`k=5F}6r(NLmiJhRU4kC7o104jhKF$&1mok-?O@}3e1zkTz}m$yfWkg?6aJ*q$7zIB;T&P&aY_4eMX z$Fh%V0f%J1R{BtNa-i?4VCHjUmtVl9`s(q&hX^tVeS%t8`4uYpfh9jjel}y@GkC8C zQm;w3+~HeqWR>fTe|y*{(b&+aX^_bV8@oW(q6Hi%N8>w?&oX=gb@0HLHG$Orfz%69 z0;!3C)0b?o#~vt4H(?+hdKP<0*Ka6TyS;7vhEOdwmHsM_GQTpAGOhqg?F*z_mJ1(t zpT*PQzm4C!kTH}=5HU<+9YoB}DUD7qwT0M?S!L^g0Y7AQt)=;2DR-K#`cC0jvIS5& zeIs`~LLc>_S-B(C+mSbv^H$_i*h{N~++?5gGOlCyIsd2SPGpY@$s;{3g$;%J$FD-! zfOuKH04@8#vm=@pF^z@p0X)tg&x)A*HF$o>&jYDOrOf6)>c|vaZJ|t?xIK_s5DcU) z+FidUms>hM5A7y?Z9_gJOl3M^8id~`fs{*A0x8pi2yev?(xny}3#7{wM*lp;ij^*u zkgk>kI!6#fx>!Yo`h%5*O{g}|An@uf)NW$Qc2}XX>P;k%p}@4hR@1a}v0}yTU;c+l z7pik%ZN@feG;iCYMYW8@{KHWxQ8${AE|LAZTW$VFYck_Q=dG^z|*{s9UbN0ot)nFrBw!R|n6$8)|6Tz}y{ z94HDU3u=uOF&s2if(sb=V1!fddSFB{QL)*R7Um$59 zUX~{ukAW+OEI?36IeLGoQ3qdy8)$-5cMiN@#~@X&QpE4(u${9h9F^olbs3%x(IBOe zk0H|V^a5P2AIrNCGsDv%FDjp>GLsL9Gd#U=Do(2jy?;f_l_va-NYf9R$k26;r=@YC zop9QN>vgcF$&T2Un9uaVJs!^H!{n5>>#oGa?40tlMMd^g)*wWAe(ETEk@1;fW!%

Zm@qVzpXf{ZS;^$3w8yC?UzmMnpD)RGNqkpdb;3R~zs){V(e`umbh{MatBL!} zEA980m;J`qHMyH_P=|dcr{g}86)?VGi0k`^WelS-|J@-CT)586h~E>RU`|M=G4~`S zm@g8>#b1Iw=9VN@m@nb`+dmxt40f9PYw|o(+#vy{pbSmD2TxyQb9}{qr z$y&1w=KCGu)|t2B5=>J3bl+_WzcG{AB$yl9tTUIiO)$&at~2A?C7Aklr^P+q9&xr` zXMX8VFz@@1MEWa6=dN0!5 zWYb=eQeak^vA(;^=(v@5i%!0c2`kNpHml6~wkypa+TCR4B%W;gv|ouO`72G&q&rPU z@@})d!%7qC_>gG`ti+b8LsNf%xMVZV{|fkFP%_c1!fwL}X0q?6CJFB`F0NnPjo{16 z39HO9yvyI(tTgp_mp`=a6!%x~=ZyBN%=>tk)BUT=yLgvxCG9u)$^SN^!K;-WR+)?N zJ`Z&Kz8Q)4@f55aWy6BK0kxdFVzUDC<<8}$*_UvwX`664Fn%7C{i+5dg9+wZbHLn) z41VS7syKf zY@4{%>_i$<+JA0Jk;YqopYN|oV_NcG&BaJ#eTM_)CA|3HKwIC1D8TVZ>wcuN)>h)k z_qaMv@_)b_1cPhZ-eR`4J7D+@W7@a%@g4r?-))8@A8_)2z^q5yZc8(!%(k?yh@U$m z;xMTW9!3u^*C25+n%`$3a8f#At>1F4_w&s+A^iMt^G!qC_2!KDF}@oT7MV6}=9{JX z#kZYruE)>UZa(%mo#fk*INy}CpKsp7uh>7|Y{#!Csm6SqG}bq&L#=tC!+djL$N6R> zej@_&%?AAPQ!23StF*cWHgjq1FE+;~JeF{BLLcC4NnctqvjImQ1aU6of%v5;%=Z%7 zC4347jA(x$EDNQU!k8RxTxvfvEaAa~z6tHx|GC}Yz+4t2D@nb*|FA7cz8x#cKYhu* z1Qg`Lc%P3<{(C~Qk4&D?HraPI3iADS`weUHi1x{r(d+%mzCR|l*UGZ0L$Z&|J|mFq z8;Z0jjqXD_*V%$R!&b;}S~uH*45v|PD`GhA#c`~FZk&vZl_IX0xOOMBaq=5Gu3vUY zwE6QCc%~H-Ebw>mgEdJ?JjA8Xx6d5J@85CX_I(>7b8(x0nT2ilnc8+!e1C$-d=nz` zkNz*s8%ZU;T!_r`Au`Vm>@#Pl{18U3Qcz?vKEGQA55aMniD2+x-#XJ4Vqze~9vPh- zpJy5U>xAFK>Mz0k0;2C4w47hH{kA8YpmQafn_gZT>}4)Y*BY9J0-2!-S1a0&oZj)SY zv4I`tB;4eENCY^GA=?tT+vEQ~_TB|Bs_JSRK9dO$CId+@Dkw^ns3?ema8s}bAqYw+ z$W;x75P}3jVlIMK+F(FQ$0${-v|@`DD_ZNN#gw;vE%RRNCULqM~A@@;}d7 z=d78`oC!#=-}nCSw_&pPdG^|CU(UYoz1Gp>aSDK2>8UYE(=UXv+;N8kCK?MBmtQH^ zF&&ChZ%$*+rsMwv>DgG92Z?{K^m_4r3&bze*KdXRg?;_jCh_AG;brm5N(e{4uabmg zIw_Hi>m~`|=r>sW64OGS)Qn6i!}z?@?}{Yh$n(do_~};w{Nww*gge2>_dJb4ezV86PzUd2xj9j(LnqF zh6egmT5rdvFS!lmzm;V03p?6du`kg;DeVWej49fm92plA`x6cHY1-+CDZU=CEKZUz z{(Z{1;+I%|7_M6U62~t3-5`F6@00KB3h_I~w@yBvBpi9ZD}Mg(44XDE{_%AbKmR&1 zHc2?fH>VZ9Wl8*)zs6SLdoD>h#`h2L^Ut5&<4=4KjPFRf}I zE{PxGi-@0pc|MyY9OL_&`1$9rgKVfJrjzl7#Lqvz(c+g_E{yNuBs}SNeG)&$cWo>2 zy(oT%CX_XK?h-%${AEKfll3#9PvK&sMm)W*(&)V8R>6A3PBU~~!cJ(mczT~r(&fr^ zf(?!hpz{*;C6|k*_st*-v*;F93wB&=0PRP(^twtsqcb1&BR2`w&$kcxk@)%dA%76R z#COXwd$|?AFO&H39epl-{&ivy#g}~g0>(F1{QTe1f+XP>U#-2^1M|1{PXwQB;lC9=UVamG>ISM+u2HdePy@UzYi%Azr%dXJGuWJu8a{k5#heSS1SxyCxow0O9dSM?g#=_c*d~%poGe6jq7l z%QKvjz{qVhel(XlP92VWupx{6R7`uWf_(#QK69RNHSDVqpb_>ow9y-3^9*P?Y^LET z{8Vt3E)^uEDL)j6QpX2V`Gx*djnVAvkRDB+`FDdw(m zP|RJiUWVlvR$v&v&Y*Nt4J$S5F2jCp*oTJkTUHvj0xNipcdqLSIsBZmVviU$04rg| zPIFx$XM|yA8+N{77aGRZw}ySluw(I-6g%E^g>XLLVOJZ*PXsI7?S^&33QV!?t}EmW zG>l*Lp>N3HM|+iyAMI6)U+Ph;-mv!#`^d0?SOqEFVAmCLmKnC(ux*BIH>?sX3=Lc3 zx}cxYu(gKuLk(5BL9Q$0j5chnVRH7`EB49fo~i7^Veonz8vQ zF32YvmTTA$!wL+WVpy?ZHHIxPjI(Ynm*s}tW7z$MZ8Gc`!?qi?!!Qc5D?iMF+%$JJ zEXS}xh7B=nf?-n(t2C^}uxkxlX4o3T?lEk=VVexwX4rPa_85jKj+^Grt}ET?YFIzR z1{pTiunC6EF|5+CrG{}X%o2hM48ztK)@0av!`?LPEyF%G>@&kUVsy~5@8r7hp>V^F zH|z|7`EB49fo~iSSn^dn&vdug>SDJcAR1T4LjAa zNrs(o*lfctF)U)(^@jc2u-gr5GHktJFB!JQuw91jHY~G~myc}Mg*t9no?#;m8*SJO z!)6&)XV_xHRvNa-uyuw#Y}iYNZ82=8VY>_qtR@dVZ#k8Hf)+<3k#$F5W^-IHpQ??!)gq>*05!U ztugE#!`2(N$*^sPZ8vO>Vfc8rTPHiaF3bfC>u1;?!^Rpm!LT`oRT{R`uxkxlZP*&a znhaZS*jB@~8MfQ7J%(j>_R7Aq>k2t}hV?USv|(cnn`PJ>!xkI1)UZ{Ctv2jo!kMp#&Xl5up=d zUAa*2-5vfPa^IX+o})s#Ed@Jbg>?`3$}>vnf19wb3Q5bAXXO5Wn^=p84639wa)0n- zS|Z;=1I4v*h;lWa#pbxHT|?n6M6u1gcpjBkkCUF;Z*dlgvZ=7ar@V3g7ckz%TjU~? z55KRcGA@;(L$?u?(M?;2<%W}y)h#3Itjvt8`FW6=tN$ltb&tgcLS#cj(Qe#&uirQ} zxUpg4o`%Am`FkTwdbh<4=0u8iMyAalU*UH}0kZ}{-b&chi6S{4onHwN z-)YiyQTm1Hp->Ff1blQZa1lG^m3-4FfNqMyG5 zQ7hfk|I;Nv5&8oc1oLD)|LiFez>9hQa7figigum__b2Vqfkim?*o@f=EPS&GswMU% za|b~i?W9DTg}-cXzMD{~S z$DoYNS(pWhbngyG`sM*c)siXH>#%1-uMk|x8rt4#(yMPz&!Njw0ZGH4qIZ>Ho;lhArR`S*^nO^9rD6IrCv7Y^y@TJ3%mVyH@1s(| zb290{DNu1H=0Fe$)=AKMc0oWzG8p!ROy611v*?+SG_M1Kh!&fSokTLZZ{3it6Y)5Q|iA0fPZ z0xk^A3;q)_a>u9M;yj(2=47|24c-XZv4_)caHgOHe$swUFavU4XLYD^p6`(69MSQT z;0;+S;K+N0qa|HiMP6;N^LU*6-K>FiN#_rnm70$Bop@A&O*JWh<#OaWE0~9K%oL!0V%E3LV zHjv}`0y2Y;+J&6mz!ZpCL(Z;0%H(^&V*<~n?!i~k+dD@?w(b?AJ*VB>&P%u`bwt{! zDU^b}9U{gTAnmuMuXRcw>Uu}`q?DIBc64$x?sc{z?I&j5>AVj4Kvs3iDt;f^BaX8+ zb+9um=A!15JRx9#>i111;eZ~IxEa4#YT`BRRUG)IX+2SR6lCXJ(@$`4?KrEYkQl)% zc_DX!O|0nf?I{o7MI7JeYo|9daeLc_lmX!JD~Kci7MaLNZ%p|;3cgpzuOXAJFLxDq zeT*NzqJg{EkXCitiuCH9z}F&#ct!BI0AKFW;CVcF-hv8vI|}Ax2yXJ_-VWZs65gqS z-YA$`!l3|PZZ6{Jg*a}@_}aM(1v3fxxDBzKA#sh%`VGXLAHvHx1>(*F@e=L{whN3y z9Oog9KO>G;5XU)b%bi!i|1aP_KK*lN4EVni{y|C!_`U?bTfx_Bi4;YqU?a{xoi$R9 zy*hMpa@r4R|89_F$d>++;Gy>3&HUZC9Q!-L?(5JI5&|(TGAg=!tQ7PKS^lESS2$V0 z>jJ+{y%f?ompZ?~?<9yV--Ta~c0X{M+m!|SLS*@Y_E$Q25LvztzuxKdo!_Qk>huj) z2Yw5&<-QPEegMBbh%DcSU+>K8oTkhvk{Pz*TO@%$Y`?_mlKOt?fYjc|3@gz0@Pk6= z4g;L4f{&p9b5fT$FQ?W7$KZJ3PiaS{zJtOV+CdA273gZMk!jy`K5I8Vt-XmZKOlU% z$jgt46RYTQO|YlD{LD7t0AGG1M3?#U4@t`k@a5kG(Ph5;PU)TG<=+&}l$U>4$8dlz z|3-)|^W}S@%lAoH-WVsk{DAZx(Kv3FUSn1Jfbi~&O3Mo6@$^KOdBYF)6phzas7(J1 z`16XU^TrmuVqSPubU95JPtA&U!C#;y+!FXDM3=P-{=!++Zn1U2CqTrvXZVW1JrG^? zy5L`C-r{(o%g;&yzn;m~mDqK9qRX?TpkGgYJgy6UTw2>p=#HAx%A6BX=!xCwlMY*6 zNqB@5{x*m%$9Ah*A-e3n1a`0eBt3(&e&VchZieXcP0-+QV{m9-5W3d^(B9Aw-D}^p z9)U;Dz5Ws1>mSnZbsh;H5%>0PP4ioIwnJ;$jtN@=ujG6iR6k^OA zF4)zsLhRp{2GZF6htADV6{5Y&z3c{@Tcmf5zGPQKnXO?G{o_QGZx`&=4mYRX87plZ zy}sXD2->1)MkRaLL>=eX9qvs1d2FEQ75-D>0#SzOZoz)gp(^!>*g(;1{G40x+eBVW zlvcV?udcUp<>IIIVf9$Z*`Jz%tKQv ze%q7yF}}CNFE61z(65*D8UFQixcK?!Z-yJrw@>+}ct(YF*l2TcKN^yAF>}E4qW#HU z2@sVZV%N}B0{k>KK(sG;PXa`xdngWcrUaN48z9<`VD1l-fxc3EEQ$l2CRh#b{U)k9 z$QHk&63UG4VU+m!msxo$eho?d_#UnnKmR(hDM>h{Wt;fteaJRx^+VeaPu7oI<#P093+zWU(5Uu9oFsh-w3)%Q z6jRnfv)WI0eEJhkn^XiiZ1WQKCmLv4`|}&OpViH~9oes!7gQJf)}Ul_syetwJ(%TyTu zHZVf`{Oe?y`1$8gMT7nGx3rb`o)W*raLnJ|Tk%uT;KXpuUpv`+^UvQX@k{KgG{Ke@onO3G)*6DgPAD zjy4HkpK=Uj3LIy6?5rU=FA0ce$O5oGIZ?17u>o{m!fxSRi6J_X;k<-$6S(mh8z4F_ zIZQlT&PxgeJI;4r(nb6d=l(30?~0#)ow&Fazw49uu})koe*W+1&q=~bofkj4s5C3A9PV#rAFnH4eBcpi!x4hna3a8+GruV zTnWH4JYyP(2M!%GT<{J@MVIe~eLJQ?YhgbMo6p-|FR_taJ|; zMn!Cj{oAlY>=-CE%5~vW@`h0*8ht}h^ytwAum)GG)^(*jmmBtD!+vVm-G<$3*apL% zGVB$@UN?*)(we^GT^GKZZWzVgH7%bQ_PJpptSB{XN7og?nTLlRYuFiv4KwUf!yY&6 zRm0vetQ}T$8b`Y83OU^j>uy-YuPytQf_d6{DE5Via>$jAG7;QOsGfCc`M^tk_n=wi&kDusw!R@sINB z?7AS@WLQ7LMjJNPunNQG8n)1|MTY&}kWEGwiR1y<^xO!*Fcu=9gm5 znh%OOYZ*|?Suu(^E5_-%Via>$Y=&VJb5^X*u*HT^%vr;(GK^x*ic!p2!&1yyF^V}W zMlol_DCVpf#hewRn6qLOb5@LE&WcgYSuu(^D@HMA#VF>i7{#0wqnNW|6mwRLV$OPytQf_d6{DE5Via>$jPqc{DCVpf#hewRn6qLOb5@LE&WcgYSuu(^ zD@HMA#VF>i7{#0wqnNW|6mwRLV$OPytQf_d70WR!*RUam6&NGQ*Y|_G`l)Fs#|ICk%Vru)iDjxnch@>~PHLG#^L0u8`Byuu}}9aI?~l zHEfz;6nNG$s56XW&WcgYS;MX}jAG7;QOsHCUNVeg&WcgYS?P8eMlol_GF_L7IV(mn zXAMg+XT>PytQf_d6{DE5Via>$jAG7;QOsE}ia9GrF=xdn=ByaSoE4*(vtkr;R*YiK zic!p2F^V}WMlol_DCVpf#hewRn6qLOb5@LE&WcgYSuu(^D@HMA#VF>i7{#0wqnNW| z6mwRLV$OPytQf_d6{DE5Via>$jAG7;QOsE}ia9G*W7q=2mKnC( zuzL)<->^-FJ!9B*!*&=JfOxRR+s1W;oI?%kVpw0p1{gNNu(J&-GwdS6<{S1s!Pytk^cgDCVpf#hjInV$OPytQf_d6{DE5 zVia>$jAG7;QOsE}ia9GrF=xdn=ByaSoE4*(vtkr;R*YiKic!p2F^V}WMlol_I=e0v zb5@LE&PqoyXT>PytQf_d6{DE5Via>$jAG7;QOsE}ia9GrF=xdn=B(Hj!zkvg7{#2G zZnt3+b5@LE&PqoyXT>PytQf_d6{DE5Via>$jAG7;QOsE}ia9GrF=xdn=B(H{!yY#5 zCBwEDw$rd(hJ}yt_+`2-^ofS`GHkVBYYdyn&lYD+iqz&#jx6jE+4#lZm%Na%*eK$pBw z+rIv*l#Hv+<-_M0i_fOLH)HXcu=8J7hfU7F7heqCnQ;v@kS+Qe&rZfQnK7Q9*DuTg z^lzk~DsAwVjB7rHEAmR@@r?Uk&A4wv^V{tpARvO1xsBn>!J9I!dVvHG`A&l{Rd7>7 zQ4fNT5G+hPb!1xg$zylm!NKR6mo#N8xew00wLSLM;tGwRX+RhM1Wt%MAw;Ag_1uO+ z`1b(&NMY`5e5+t@ZD)M*uxQub+HA;j?yb$-TN`#m=PcPrX7RzjWeW#`WDtO>iE<#PZSL6KO z7q2w&KM{Xd$N7)Mo&opbXgjDhn0SDi3DxHH(eZ3_4j?ni9ixYt9*O4^A^a$Yc(Qw)5%Ru-X(sk>m(xn0$7MH2wI;SsW+}v~_9&?Zpp;Bd@B5_^l3{?GyyA z4`d=W42RN%*(g?9OCjS>qj9p@@$jVc}&&VsySnr zoq;XR6R21ycD(F>Gre}Eg^E&Xo>uHy+=6y*g4b56()xu=36CD8)32sOxUrqv3t41y}&3F#(J+1)FFqL zN>W*{O@e*m+>9Q^tCWz6IIm^MXNBr8Cy0M6h^(0C<<7EXaFY13@#;0>97)*KvL@2KF@A80qUOVNZd5H|%M!S&=ZF)HT7L4x81v4EEEo zFM|Cd>{+l`g)3lhgFP4a4%nB#{u1`3uvzVKhp~=t51&=3D}=oe_9z#h4EqOoz6^Ff zZ0^rr4f`jsAr?}{%8Re1)$y+5SlIWv_-|l;7tc*D{?%Q^@6%Pzjf#W_};1^ivu zBVlv=Ab-AH4zTTbq9U$z=V8|slG~p2O?TcmY_HJ;!Gpd~rQ^ENojk*e4MTalbcoT7 zBVyQthW)`Xj>{VFTZZv$La~1vb|^+<#k#mI>`5DTvSDKkJJ+x(!!9%ID#NZe>~_QM zG;E_`PaF2CVQ(15GZ9T6&qU}7IVZWUbf>pr;|!Zf6>61gvm>ueZXDt? zztygxXb-dlG%VbSxo@BR&l?u*nz=0h$w+g3bDR2Y8Nm&a)cS^$`o~i1zZ_fjZvBSL z`nkITwSS2~p};4RBFwQfM{X?Kg<9y;?+#q{-N?dlW7qceO!H?xL<69b2 z+14FV>e6kv<4m4(E;|Rz>GuRTOddN4^Kf|%)_zdGzB72&zaOZ5J+csU@Ld`AL4iSS zcv7%1dn_j7;31^QL+44DnJb@(dl+tNW@Bn!5Hy~%xACmKkUWf}=5=pg@&>Y8Qv~00 zo_}{J(iNE+j(nMM-(!v8zT?M{?IdB+z3>CZHQtTMf3BFptA+;fVWBqQH)<%@p&Oq&}B^O@6x&3m`9)({v z#F#wSbLQG=u47PGTuf#=1I&f@n=mP77s8Q-KN?QTxs)I+JG1$5{tc+a6vCk4xK$PB z{}TM$LI{$Ed@hdj?;}CUStsQ$fc~U7AxWl5mNT$9^r~4@jc=#gP>zqLf@Y|UlGs0n zsR@)iH#obUvoOg>J`UnU%q!>H%FCT6lG&?5wZby!RSqu^ECeQk zHxnoW%NM}}Fu{)VC-fc1IrYc}Gs-Drp5WQwr}NHZ<+(gi48$uaeAq$wu%NyY{|mvV zlhX&w3-aOIug)#7Xqal(k8&zBDF~s3%T*nA8jzBc1Y`Q%5o{5v&e0MVC(@d>+Y$0Y zXO?q}rP+&%b7f9*xf13aC7SQ^EWI4zDeIexasO~P-+aMcB)wtqJTr^)(Q=_XHo&EW zmffV1*^)Zu`e>o<3Lar#MTEozk@Rrex=&J^F{pk~d>$ymDT}6sQ$pcj8~PrNxhoE~ z<)g#=@UZuzq%nV-uSVZxY~|v7mGenfWsXE=$`dOeCy-V0#Fx#dG4ez{tT>Zos>vF` zCsZPtM>?MXNRte~0mC*u5;ps!Jp^EOI8Ggti+W$js6K{$qWjF(0v>gJVSfsHl@?1{-|pR=~zvth<#KY}Wa<{VBev|a|u)$06$10=~ zL%MWgNLNT!Zi=x7S8SK-N@spujMHAF<8npmm{P?gt-^1RVMB~=q+z2CrhL`391E=6`OVfKs`SjY0a>o-zfq-UNbZ~S@ zU787eM4~`*rRx*5de@XMsL7ps2@xa`G*7zS;Uj;TRH?jUB1_Rlc``+a8X`8@@843nigWJQ^|7G+}4vAyaL!V$^ zH=<;}MU$4mhnreKh>3H)=L{dww`Batp?&)ga7v~l5kn`Ao-lgUnWr6#Kf{V99NQB7?&#rTh87i$KQ@QOiK&l#$bO*{kdAKH zX~i}3=FO=to?Cr+^?-iGv*yh$FP>XbRyD7XV2 zeT&a6pHp61U0!@ypMHIct7}SYD$0s0=g%swo>ijf8q&)8<_)TzRf^_Ua>+cLar6c! z=QIb`RB|{=IRrh;A4<8dP`ik6SI?VSlhfne6LY>>SyM5$;);q(F3K5(k)vWxd6nkj zUF4&Kla_UACOU+YxqbQ$!sItiHngj_vs_YxTAP+N4Ykhe6STvC2MLcs`1xhCN~`dE z7@n8J5K1QjJOenZR&B*4H3Ry&gs~iDv(;sY%n0Ei_qhho(s$xH6O1^aC8Nq3M#-cT zag!RxD$L4_=<75T~et+n$*Z=#ok}v0%`E6N~3pTry+c{OX*GD{88X z`{Wf@Tv9ftc1Agzz4Lna$?Mw>c5!W4RSoK46{<_`S^qhwvU!+@RMnKsEuULfd3j0o z!Q?rAU&)jbUpV{pLs|6h z+n+RE2`!jA7u61BqRHRC*50!1%Ngao5^dVWeoebrn)ZG){xZIn14)CI9k)BGtg5)I zw5D82VxF6||E%83m1zYEDR)9%PHy@1%AC_-RaEBixnEAtoC^g2PCy^3^^vORM1+yRQqotL9@Cv8jK`UmDlNHRtEA^zTqeXJ?-oZh9oyN+_;#QnO(4Tu&eRAF4j zORN7^TGa)OBle7MOkLJkvZt}@je~d3PaXW1>cYtDjb~*>Ua5a)ch6UG2@X6W3-`=i zmXTSov#}s2BQtzmeRCQ#VQ$LE8o4c+a`9)*u z^*y2bm#1rya9(3UYM+sN>fa00exeu9xK8;Dzs2}@W;Gndy<>`c%sctaUuXQ5x^BxZ|VMZkScD|Ao1%8tB-(*i)-{ z72bBhnNeQN+fsU_qx&Lt*aOG|mi+vPTlY&PIObw|EGou(2Z}&lkGSKX9LyxzDR$Uko~?14|xv3!N_ALZ>T)TVCp$?!4u? zLQ-3mj`v5D4x9SoO6Rt|i=ARvzG3GXHr23&hAlFTcOx|pY?ZqF?lO#0p&IWahBX_O zgVv&9b6uC5vqvU|aqo0e{^yNn51HJ!V94O+`9}@@S5=puoBxExDB5PG+cy6xZFB15 zk$*Lg%aT5d+>(4CE=*z$ih(@)r^_6+_v;+J^zQ{-&TB;4sTnG=ifG_RkPJ*p#)BeYqgA%ad6LfcYLcY z!Sb6I zeTq(UvL>wDKT#h0)vWZ)Ob*Sa#IRwROv8`dM&m~_7%hRtSpd5)?6Y9^gN;qwI_^ag z$4{QexX&z8(lN!y;n&Vt;kweDm98t~G#R$uuq}pdHSBA{Qt%$h4+?NxS2_>RTokz zew(N5{ z$F(@7iS)n3Z%=HCYq=NCacexhapR(b7m@Ym^Q8zxRn|f5^6D|ao@1~_gwg6`a%pt1=D+Z?yq^Jced9}Pw!0-g7;6>?;R?dK` z5bbxfq_?ZYqi5E@F%7?T{AS=s^BeS9?CpLByEkl{k=3yrABN5S$wy$b$83hpUT!_? z@4C$-wT_NXhu5UW8B?w)};p{=_{%u$X^k0f` zG}EyC4C4X3Vmx+NIv%?#Hpj3^!|DvuT5}!_GHsreU)UTW#1H!}9QIG>(3*%e^O-R#2h!d&Eb0$OdoXQa4vare!?S%}{L_R={~OopBBK!68GmG2^}${bh(=CILpF7BWOl1pQ=)P)&Vg zh&Z$!pbXI)HFLvpK7KoBH~ z5edlUO{{DY31hJL;C(E9=rmEl$B2tVey+G?z;&XymKk;%TseaM&RkEMYn!=JK@&fe z^7N4XN-z9qIFv$W-ytoR7JrTN|06(ea!R@_asF-70J=98na(@o{L93jorZ21^uf?O zFiwn!X(I2BV84hCQB4amBH4*YulfH3iH6A~N)}N+DW_`!GXrg%1-^nrcLvUOh6Qd2 zs31{i)-RZ+#5w>$A|20O4nzWNAjgvC+yi-^<`|iu9AVEt@q$F32AZ607%03oe2EGY zah|{x5vA9P0;5oQQXv`F!Pyieoy2CKCSH)}QwS1m!qE7CUXW-Rs_*w@=F;Rl;O$22hak}^d5iIaM7v{{BoQR)hWUhdCDdc$iG4LO zrRXzmMvwH(1dBXQGF_Am?@O>~o=h!sgmzzoMT;Fj!J@CxSN!h~EYhQGPK!LlK64r# z*gSfXgIo40|?gPA=xcrf3my-u%QZ&$`QD zSHr#;_GPeF!k!PC^@pNDzk*!=`vDh!5cU~(e%!@3xHvnp!N55lk^T)A=lC@c&mX`> zdDU@DA%BiQ-SN|DD_uHmr7I+pRmDDZ=|a2@D?VP>i!JrQE1EyE5r60b~r|9r90AfLA{7!rx-TYunC6M7`DK$#fB|4><+_t zr&H7Xq+!n*_L^b5)2VcO4GRW6te5M87?xq<4V!FOnPC?hHs7%C8MeZ(m4>Y`>>k6O zH0)W!-Zbnj!#*_ZW5e)m2e+I%xvr2ym2Taoz8r5@U&96%HpQ@F!{!)PY1mT3t~G3h zVJi(=YuGx&)*H6Tu$M5S()4X{UG6gC%G;1?C;th4f3z@d{3LwB9Rfg$Hx@Dl_@Hv( z!#K>q=SvHpft>?;Yous9oOzML9Sue6B1PL8idII7wl);4i4<*VC|VXNda0pkd8BA_ zL(!^8(K8K2_e6@IAYetLXgxwhss}q!yCb!`AfD4ubbq9%siA0Xr0C&>sn<3XtqwjN znR;z=bGtqabx*Kpb#rt3KIFV6SaeTwbBFxb=zJQ)%};jhQ?xo#v^H3@N&+AeE5+SD z|I5f!Bw%ImIfUp#?rY&BJrcAo_%z7#Kc?%?!X0V2pH5+ZKbbF&OkE-L>l(u;q<*bo z>Waqj5s|6O5Q1q~K{7ma$Zu{82SJ)IW;3(7$qKQdXe*zXQ>1?-%DSOwTd-)2W|qN=wnN;?&GNMn!a}Z@7C1*pOL_^_@Na13Lr!_)Ct#%iL)EY+)8T{D%QyM2eJou@q z9+6KT;;gXePCfDp*pb%-5KYT}R#rw7yaM?j&__6pwa@h2+*1$N3b3U`U(0D4 zYTix&Z9QOT{kwtMSHPy^!u)41Fiu#HI6d)e>+m}INpNL5FPe)rJATQ-3yxO;rymWM zJcq&NGiRWGiu31|ONvWAO95h33Z;iW$`Jj*AuVB0J9hZFkOY}(G>3^Q@RbeETy;8F{M1E3nrk+H}E+x<8{C^ z%>Jm2z>Bj{cs`FM#GkOP{RljwnhGKqe<&q)v`dfVIM)dMYuLFQf|MQW%ycU8SNU) zIFmaAR30yeD-pkb@arA$(oXz2;f1frx$$-ecAn4{gSH?rB0zyE%`5%h6u;92W7)8* z#|sv;G!o+`6%TPcK#t8TmmDBPgq=0uJr&1tY49Bs@ceV(bC&o&1plQ_>6#9KtFD$_ z`oAfBkHMy@mJ=5e+?wXnD1?o?KY`~a=LP2uth??DoFwVwR%9>yhLX%lPw})&rw-({G`D@P)Ijo=_1ZOyD6V&!h{GL* z4u*TWY%#LsD^KLlHaZ2q?hfxPEp_3*K4ThO?DL9UyxM`#6`t|B>sUQ6ht0_Vp9i|n ztVVq1NiqG|MEP9nKJ%3#$#pluMm4B=5cUsXKMosJrS3V{SHXTAHulj)_zT@YT^iD` z6m}=r4X}B36@kr3^0lx}g^li|ZUpS>V2^?QBiPem-vArS0amBFD_}2&&8hN_VgDTV z&9Lu>y#n@n*gt{&JnUOwZ->1S_Ghqfg&jb-tb&~j`!?9UVE+PkKiId!9tHbO*zEV$ z!2S_z>}J<3cX9T?#QCaDz)zP5bm@Alr=yTdS^m23KVLay;P8}_ncuNn5SVJtrl+a4w0rrC9c zoTCgo#xUNCR=U#-D>7`HVWozZ8+N&23k~~;VYeE_X@bV_h+$lODE7QzpBeV0VeNw+ zT?f|{a*i|XM8i%sj3Q&?9CC^b8)sOlVdaKVWK7dStp^&GV%>^08g{E;w;A?;VGkPi zgkfB`D8JVX|=TE>{!_U_@37AGLF_Lk;U<*olUnY}o0B4K-|>VG|AG7b`W6 zEry9UgRZV3gRVSCZvIC*d~v)nb)cy2f|i5kx6&e;o8N8|{BuK5*M^B7EP0{ksK{55 zKll7Pqni^+&1f8z+Avh_M^P)n!rk=?vz?5|ICMUwaC^p8Yw=Fzr$>r1mpqxV_-;Hz zigrY%Vp*{ZYn0}XQlK;8{U8G7zW_x5M`zrJ_}T@FI(ymxQhyBoXCi{ZuU0`xLU`QX z+OFeO$w2-3ObOH#Gs~eF_Z5XTWF+;*m>^I{h7gnVFdT#k1Vsq-&5XBxGu0>zF3irj z>U-$0=eHkRl$mi=C7jeu0Br>=GJ+1znV-g7T*F*U-8l-YtH{FbRQgc3(@ih5Dny#Q z4{L(d}ZPicb zw;8-Jv+71k!-X8d6JMWo`-O}-bRl%jc z*BN$;VW=qy)9}B+mqS!%{Ak!6Q)Y^^?eKd&&VO}V&Q|Hmj@WV7nZ<_x2>z*{pdp{l zasH#pROXd>@-P*w;&ml3O$_@MZ0;tiNvZjPrUo!$ zG2=WNGdNutL}w#$2mHu@>O)XE&Y;yO9p9O^l^yW5vN?6^C{%y62)vg|c3igbg{jFy zAFB${(r^pNo0iiLa}Aj9V?{R%6aOAEwe|Q6le{bx`YcefpuZqF&ZNUQ6FnD`dYzuC z-(}**vkgvnwIG_r>L%&gj%GSdXqHHt@nW2vz_?AxS%pqvhdR_ZaHY^yV7VbvU59!M zmIyX2(Cl0hlOO6{7$)ESr8l-qVNOO`j}sbB@VNN!w*Ptd$Mq|3Hn5;ECxbaFa2u)x zH{zL|qXpX-=oy$F!{dAj!+Oe!z@`*L(_!V}^n8L~Pf|n-oK{=;b2;ER4+gr#OkF9Z zgzF7$>mKDLhitE|Lb6bjc?beDOR$qM7afyzOkB`#u$tF5g6+v8jVuoHV}V&9jJ|o! zHhB+=rNFm)l{`~R2A>0R^NBYPPIMMZl!wMdDY_bhi#CUYZDSQR@Y)T3yrvp!a}FM@ zcwQeM@zw30q6QYPDr#U-`2tl@1G(}EhdG?Svo?{mLMQCHOTQU_XV||?!vmYjdKcX8 z=q^1bk97sW{t26}4pYcFw%Jc%-wPYnyzWuh|API5`~0H&{1)u5frr7L;ka^6!7ev; z^hIw&1#C=2MUhtq>>Kc$1)Jx^q+^rFhRr_nP}ncJ&#$=8oG#Lz{o>)U*>CW4SEt5w z>C~7m)xV(FR+la$qJ4_(HjHNjigk5eP-1HsSJujJxM4V{aIratRT{R~u%(9aJVE1F zW!QSdHW~J=VILayZ^Hr@n=~yQTvxi2W!TAv^)ZZ#42_o)Vhuahuu{V~4OTi%gO#q) zupb%539-`MX4nIU@k1vX_6ftDH0(9Q-ZbprhG9T(!ye_j(w$=rJK3;4h7C2W(6Ca& zI5pO^aB8e+=G0g*PKXuzkzwl%+hiE8rYjx3yX=PTZrBNiaWhTn1{y}8e#KH<*SD#Y zK|e-^N^K@qavd3>&H?lD9I;a7NH}O#yIx%ipKZ?#$Cf$}kP*<-0cPJplT0T=rFuJO zef4AXxAA;92?_>y8pe4JO){MfSOOys>^d#qvxmcX%k&_L;Ij(Z>kb!9GMx-OnI!co zqwd7W9?yp}xnO{@>F1CMjOt{FEg$wa!2q{ASejoxiIk2fhu*=_`Nv$3up?NLwI5>T3|; z3WBME&^4NWV8Vt>Rsbb0p->c@{GEk9{=vo2U3&ej@RG_or8P6>Rn7g+H9hEZbUM^`uLJ9J75v<0}cq$ zMwP8Rc!HE3Clk{AA1BWnC%3Qll|55i$a;Q;I>Kp!pRDH`;Qs|#Pi#DfCr!@(Jb!QF zurmffUfp2_;&pH3zJI9uoq*l^K*8RcwvF@8sQ-JDh{!D28`+Ri_;kZ*B@I=n7dD)o z2C)?G-mrOO%e>|YaWQ+J;kOt+&#)(_aXVgAa^;yD>p&D(=H!n1Tv#YLBt zt1foVWjO=Hh=>zZk77F1?byBmCw4rN>6J=zzbPtx>ZOC;d@D2(0(N}aKLISh>=}mXXWIDnFg11o zzXD2mO8m>-+tbwfZR@>B?2aC18tK^03%ASkPR+e&mmSq7W$h`X`+j_A^NL{|vn;+`IFzAeRmX4o$bOG5?IuwmCF7w{mylNM zMJp#bsL4TDm8gEL7=%u*26LYV#Rbz@{xYW?;&o5l?@=1eBE;yv(OGbpc!OU|2W(i( zfY^%e(9kJ^`V8!=TP5;$Upp&(1`ULk7aH!YoFqFdlZVKKAxWLz&I(UzTNt06mCfiB zUW}uY9TU}g%L5QGSK{yO8SaB?30>UI$_Ds#L+|l7{AgGc{dO+4qir0HS@Tz%xWTa9 z`|VutogKx_A;$Re+X4S$K-ZofAq?a7(Q0{62GOl+vFc%kL}DeZ-0alZ+qB?-;Lx5=wu5EWhJGm*s9v zCgaEQ8|H0a?t|Yb(DlzzqSp9bSIlaHqag6gzALUrafu@T){GAFq z$#2z+(wb5Y%fBFV#t(@;(^Zg}SAc=)Kz58DMDY3F){b#2+JX<(?lG&=!O|3b&@=*n zL;b((YS-Y$s^+J)cdp>S8~2y#hg=b^U)z4d75y^u(G~nn@I-CFr+|^4w%~ff6SW2N zvV)(N-yGD{%s`@6;7<|n)93!B2tgHbHrxzNGn6)l*kYEIUZ1JU#x^9H@7`mndMIXLQjT~)vbPYW${=DY9p zV3f1RD_RhyJ@#8>A5+ezv=~DVchA%C<4N4kPC6~}JBhm(H2;N@xcU$HDZ}uj+0ftP zeE>XMzpyL5IQ}D~pej_qurrhsErA=~DO}Pt|NB)P>%ZPRfBurD+BQ(42(_$*d&V{v zX5zOS9~bN;AMnoQBoiMP?+mKbB1OCNU%+<;(=vYbRQ;DZ_*!_zu*de+?#bU=|78K3 zW6zxp5dS;lbK-8m9?`FR`+VEGd@pqQEZo}UR;#zAiPDMY% zZ#aIQ*#HOMOAi-VjX4Cjw@6F-H~7W+XK~)_ZWQsIW@FkvGH#2OJQ?;e{NBgARR z2+LJU^$>()kq9%d>nLRyca0`c~NV`x$Jm6mN$;6ZRU|D`DRQdll?EVBhCH{}whdxoC~HUdOgZx-jf= z{PY-rE<_iyL4R);}(O`^)al!VM7foGz^MW zTz;1r_EW=tX4n&kJ!u$^b2TkI&eeFkqnA?b1lJXEs4he?stZxNnxJ8>D@2WEkFz8A z3_rep&k&0>^TCCNID5Lw@H;oIr}M&qx$`FKm72PJ_jD!GFRv-D#xDGVgkvO+3v9Fi z|Fc}i%NoOYbMd1&1N5{DU=tq-o3&vwetJ$wm!1>Sr3XNYJ?zo}V>R|IpSJLbHTzRO zUYIrrxb;BF2O1{hkJ)0fJ!;u*iPLR#zSf0bKS z^=?^B2c~63mzEV>ArTT$Y!jXpJJ6PPIXFy=E2&gqG_2WwKd_S8-^P|uLX11UHle4l z1I%7QTHAcLgr))05~52>h%W7W6>GvXU0TBqtTy?TQEYAc+X0r*em1y-GV-fM^V~A3 zgv}Orsar;z6KEOHrDa5ymXTsjcvfs3Tm=Wz;(maT7sS=0*fM(Wz{;q){F3U5{cUfb zAPxI!ZH;a@;kJg9)AepS%|KW!C%Uwp=u(~Cimk`9VkoDy1M9i>)ieF$82RIMdSI_j$0hZCh?3v2kGD6Fd7KhoQl+je=U(1LtEhDD>b>ql4ZvUE`M1Qn#EM+;T$sx#dKcmJ?mtGbzTNNwEWMZ5UIb z%Bbbl;Z$HWLHz#ujY>&Zg8Mt={sjDE`)$S>KL~VzW}I6-=fY-s#=GTnKHOS9bZPm}rRAd-%SSO$XmaIkc=q%qhF$F@+0bs1IeX@8 zXM989vK=JAw=tkaeaS{Tsd@cRa5NUKzz*h0{FY-E6PuA;u^;JDa~HF$v2g3`9K8oR z`?SWwRbyx800QmGy|pX$)-HExb8%gCU}NE8yD^Heb7s#R&k&RM)-H?j0$V=Sp5O*e z6}yEN@)jESJhJ>I>i0f8nS6`qQ*ToleV(Ese7ed#bG{*z0z6u%aht{k?5Zz zt{d<`irG|U2bdy$g1>^jSQBOR@BCJkd;ujl!4g5XDBIL6x&cB`1f9?tBj>a_9 z$I)^9E7QcV-1qswn#g|a-Im}Jst)&WsW4RcZ>isb`8b>rI{$VagzL4KEmr1Jjcz!m z;UQsLl^co6u-kTmP=1c!s*&Und5-E1WMDPQjM?F z!$o>;519!&Qv5!5?nldg3CZ#{qqX?xsqtjO)yf{MyhmZB;m%>UASd=YZ zmKNz^ws=`sgep-R(z94VEHKBQ#S`TdhR-`6`iMH-wJy(?BBtD0rq;>FT#Eq_S>-Ef&D7%_hG*U zd#8(k4I4dL9oskQ_&R3dr(!*H>2+|rLe3u7H=VUz=d)}};hGC=BjhE`BH7!&xt!Z&kr4&nbU9PI(1-BuG z-q4wip)-@x4^#}sp>vWqbT*DD$LKk@xprt{;nLVKuFve5GIq)!HG3w9(McHemQMDF zFfcMmZC9ayXrKG_jl^+GLVI8N*a=QxErCRhSLeuv{AV!$Dgwo{?U3&1;5HFY+1%1} zhc8GFxQBz&;L?Gt5-uzXL06BzI()GTD#l7WPkisd-%G^xd;C>8lv={@^(e3f_^~R} z#1CJ;02b@NE7)@QVik_{FF+)*!xvK&>;H2m0!^6aWBi8U^~Ns`m?rk2cj5OTdLlLZ zIee8|R$f&x^Ku!*x*%7O9>kbNJwF`5bU>)b`nZz~29hF)L%ZuVxD!S&RTSinHaB6~ ze~2+)05!^hx$_&fI0{l@sg8ne0`HF=1CoH$T4=o5nMw zmuD}>QM-n;kU*@F0hTO(CI}Bo{f8PRX(>YY61p3qx#|2YR?2^(*kcC+4g}4J|2q6Q z81R*PCYsD-g8|gJREJX4z3&znR}Y@%3)I^)O0&2dwTW+z?r zhp-0#L;b580ecthb76l0n-j;~u;;_Z)U0kHY!rW81lCu0UIrT-Y8?yq->_Ln>CbpB z!cV(ky0i{`QC8n()?wT4kDOVdIP zDVn}73_B97P_b^VE97i9Y=>d%*#92TN{%D$xVUL*TVOPp@j7o=JKvv!H&mwmU&!s( zHuq$_OQvNCY^DdxdU>Z8z^yAex^yK+m#*X#!%#2RHxzRoN3qI5qkg&QGd$(u=NT{8 z-t#wI^S=E}ORBP}d}hUg9Z@o^Y(?nwEe})OlDg0>sS>xOib10#MVFQoU0N!NJ&b3? zWX%hOm0_r&#K!@aJUPE>RYxd?Y?vBe^c7!4b*KC%|44@_+Z3NjZC706fo9M5+H90h zKOtCcRqEi^tLH@uJI}`4ibWr3+q^Ah>^N6_=ECgAmdIln_dFhWe#b_(KIqTPoVhGA zF#iRN#!qJa>aqIWIT^#A%74CoH*WMiMSYsrtOXf9Huhr1HFv|+I3m!{u739!RZn4Q z+9c{JBMY=Vv0VFU}7czZW9ykcz2cBqIOGm}Eqt zV{_P3NOQ`#bDMXhxF5V+@Pp2kE8}APJj09f9KQIHX*m36z$R@6{KmxjQ>B-uot{DoXUF;XKuz%!3y=@H zu~_~~Sd*kv*5RM(yYk|`ZOJq->;>WkwtQ( zgcuGT>p>Z#sb+BxN=%9ix(uip-5Yl`;~9YEC$w~pmI$~;QQ_+rFj?#1Kujen~QKphy^~D z|54qY(ZD)qU_QBAR0dr0B-gPSrK^$&1k0X^qS>y!3Dh7yLc#UfP=D$1@+uFL$kk<6 zP*6<1J8bBpFI`Z@c%v#R^MxlrhdE4?L9px;JG|UOekM$ zEOkPasGaFj=6tF`(o`7*8Ee_=^%EHen*e%-?Tkzg#g82x4cv9?^t-?&gCk(~hmBWS zHwgAou*bqa8uobD-C)mxoddfL_A#*Uai6)W?T6<-!Uhky<#YmUmQN4ZdtmdqEz;2o zHmg8y*!=w9DX{r!`@)_Cn|#0UPMUBjp%QsbaX z5~VxTb%mV%hMj6yp$01&mnZV!VAzsRGC_Ec&-nb0&@|)IgWW0c*@eGedXlMT zY&~C`wLs-$44-7G8Cy>eXCN*4sA|U8a?TVQkI&&njYwL2zBmd613P2VlbP_oILZX^ z5gavlkN?NN68WHS2Tg4GbV}fpEi|o{4|@2xd}Sx_IZSB0^qjc%*BB1s^TpkTmgRF; z0w0bp(R?kN_Sl9*K41-+*z(~O?v{!jFbaXD^?Y&C*RmcSk-&!&lOU#gY8tye^ig7Z z*s5Cc>6*X?qaSFz@;U6}{uq|x%LgN49G{~T_~Zx;cau4np8v(jafy765gH2mvZQEo z68IboG#KEP2V2qC_q{$MkxzG_DMse`=4g&h;FAk9ny?Kg50_#AJ1 zSSp=TcA?tR6|49HBY#}^9G}1kvjos^o`Rvnx$WoI9+SxDM4_P|@2POn^bkIYDpX4_ zqbi$Kr9_UW_`<7IQFR%ZbBKwm%b4aOT`ko0E^>q+e{zwd4PhTdlWPcP8Z^fna+Zr6 zX2=2;$u{IJ7onO}mV)RJ^RlLvBkz_!W|tG))P}iwOuvzLuf5CEXGUx-Yc{(xaXk-fOlL zp40+i-M|r044>XHBH$+hkM=*WpR{tXdK>n{Ye7oywjfjA)hm6|8*L92l7aW=e!6v zhH-(Y1W;A!B{SyDRq2oEwKJiLdftqR+PUmRt|+gX7yDc`x6&zz*}7^~Gj(b0oH;Wp zE_2Q}qhwe?NnZZ2Glz{Fdd~2(3$SoGBX{V~0)Oq*`F#iEM9sc*EcNdP!D2DgvD8L% zEOo)`l9NXoKOIY3)hqhfN5@hg=0oX$C<$E!NwilF=ISHH2wj|xr4V}4--E7Mx7%cD z;(_SqxD&xEzBSz((=VPev+v2(vr7B+AMl@Rp_Q(9Xyt7O*P(lU()mwHNT%J-$PqZ@eij`EmQT0N_zMfi>&I0li; zFPl|bRZ@ff(lpuOt3`)1pdSDd*|sON(_FMfJHK4-l6(Y%dv90~i^_7B)T&zhw8narsfc5MTHK9(U;DGlLg)&A8?!kW_UX{AtEDypl09quX!?nF=ev zy$>?q%5}D*x13{RN{qRYan-NSt=|w}GU{Ii%a58fG8;A07D<5*z7_8J6frqfOXjB` zDOdATjFH0JhjNglo>Fu?%{}WeTq}EcY-9<`KPa$!8BEF)m(hl5={64C+q|t!gHQ}E z%+0u}5dlgr&=)mpGnl&J_$|n^{AVwem&q@iW8Q<4B-To7L190D)3~$nm%E_Zyo>0% zo`#EiOxeycc)v==(+;I8giC!Nh6|M&bd=cUc$O{SVZeX}7wi0I_$|iIGn}TeD(1LA z1>D@PBQ5QJfKROdFZhndS7j%zi}U}d__L*{1nS~A{~}q?GY5Kt{1zh0kGojHG%@bo z2)l*Z5wmFQndb~2(YIv$$f1~hVg3RQ@W`R3&H*KGW)`c@2}1o&z`LZ(-B9kDdB>g1 znHoLrWLkOMs}{D$ELJy!=7k}Yo@p2L^AfpSGG$cUmdnA95)WQfnoVLFlrMxAeKjfu zjg5%DYLq$~4?NTD4!b?XczB>mjHX!rMgm?;9`41&ty^9x%Rz1f4i`Cc;)>#7OLv@C ztay0Gh!v1|U|H)nWsc>6o33g!RXKRz>9FQu#>Jzd_rpsC{nRLJE*_Wz-o{PCb$sUF zr!K{dVrL0z^QAg)WYD-)Saqn8xKBfVv^tc^ za|O~kL1_4`NDY&M-LWxQ$K%E!TgXFrFMo7@55xAJ>Gp0NvLEqGv}wfOI^=mdIkIu< zRu;Ohbonj>6Cb^D&b!{A5khH(yb#WYKr*j!@o=4ufsLpPxz-EmY!+-3JZxtrWeBax zq?f9KLY#n32BA?(tQArxm^i+Az81GOkcO{?kh~|d@a~{bL?Pj8?D}!Xov=M4{VpDk z#BaL`^3288O0XEytMA+Qr zo&uZW#rd$=cV7UT?>PfMJ?*DUPy6W#Ie&M3)8#Y4ig6{TbpLW)A+#kA>*%^d&S{46 z#({<{HH;_wit#*O`CV?`B9(HSA5p-ZJcC!#*>tbI{}0 z)pdm&p3Z9=Je{X2u!Cz@A|m@D zxPSp6Xb=cy5tOPILeLnoYPFkMq1Dz_>(aVV>jHv6T`DeLOY2fpY^kE4QpKgs|9R$} zdC$$g=O!^g+wcE5`Q6N%XWn^d=AHG-%sWT1n-#lTv3nKEL)#O6ovaHx`-&AP#+7-Y z8=%-3ij7okDYhGh?i%X~@5569TqbL5T6ao-?Vr1S&#e8^ha93C@2(*u*s~0j7{s-y)ue$>~4@>apV?Ds_Sz))~YcISbU%T+*Jdag5 zXs!D!gD0=CuQB)|-#>mtw}K^?-}l_o?Q@Qvj3tU*U=*~5Uu*E>wRg^+g4XJfMH9*i zC9lbUf_T3`_1$}G?AXbhG5@lXN?BwNTJ8OBTKaBuykLsdcD%n-PVZGXK=yE^1h#~f z>-u}RDG?;Ema~jsXRj(RpHn$yZslc_{rXI~sC;he6eIU3l@&9l%qhD-_FWU6_W4GD z?!WvemfFAhU})w1CBy|_R1 zM@*|ZZ4BC26u%G_Ns8m{d#lVHs2mN1I{z|fpj;n zF8I$$Z(FL5czkMWF8wNi%iql4{M{M83-OhS6g2ZO;o!W2!sPUR9Decszr{O(d!haa zu6#U?NZ5=ZPx2_okC!HkX^A#F4lE^YQn;0JrbvvelxN~$4>utkYyX{5SaXTAb(;>* zSVN+kRyeB$cdiIKx}fa>f8CjiWWq0saAN$eg2o#bjxyg7A|5Vxvv4U_i5aW7@p~w) z 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∓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�-*i2MFK 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ⅇY!POx_s`_Q_g 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 From 50a65841bea5c604929836468ace95177b3a133a Mon Sep 17 00:00:00 2001 From: ceedii Date: Mon, 30 Jan 2023 13:34:37 +0000 Subject: [PATCH 02/38] Change default DAG directory for `etchash` and `ubqhash` --- src/Native/libetchash/io_posix.c | 2 +- src/Native/libubqhash/io_posix.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Native/libetchash/io_posix.c b/src/Native/libetchash/io_posix.c index c9a17d845..b39ccec32 100644 --- a/src/Native/libetchash/io_posix.c +++ b/src/Native/libetchash/io_posix.c @@ -88,7 +88,7 @@ bool ethash_file_size(FILE* f, size_t* ret_size) bool ethash_get_default_dirname(char* strbuf, size_t buffsize) { - static const char dir_suffix[] = ".ethash/"; + static const char dir_suffix[] = ".etchash/"; strbuf[0] = '\0'; char* home_dir = getenv("HOME"); if (!home_dir || strlen(home_dir) == 0) diff --git a/src/Native/libubqhash/io_posix.c b/src/Native/libubqhash/io_posix.c index c9a17d845..5e3b35e61 100644 --- a/src/Native/libubqhash/io_posix.c +++ b/src/Native/libubqhash/io_posix.c @@ -88,7 +88,7 @@ bool ethash_file_size(FILE* f, size_t* ret_size) bool ethash_get_default_dirname(char* strbuf, size_t buffsize) { - static const char dir_suffix[] = ".ethash/"; + static const char dir_suffix[] = ".ubqhash/"; strbuf[0] = '\0'; char* home_dir = getenv("HOME"); if (!home_dir || strlen(home_dir) == 0) From f2747baef3980957dbecbf58cadd4affe70f3ce7 Mon Sep 17 00:00:00 2001 From: ceedii Date: Mon, 30 Jan 2023 14:48:27 +0000 Subject: [PATCH 03/38] Change default DAG directory based on algorithm --- .../Blockchain/Ethereum/EthereumJobManager.cs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index 735c52f32..e1a82b769 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -349,15 +349,34 @@ public override void Configure(PoolConfig pc, ClusterConfig cc) if(pc.EnableInternalStratum == true) { + var coin = pc.Template.As(); + // ensure dag location is configured - var dagDir = !string.IsNullOrEmpty(extraPoolConfig?.DagDir) ? - Environment.ExpandEnvironmentVariables(extraPoolConfig.DagDir) : - Dag.GetDefaultDagDirectory(); + string dagDir = null; + + if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) + { + dagDir = Environment.ExpandEnvironmentVariables(extraPoolConfig.DagDir); + } + else + { + // Default DAG folder + switch(coin.Symbol) + { + case "ETC": + dagDir = DagEtchash.GetDefaultDagDirectory(); + break; + case "UBIQ": + dagDir = DagUbqhash.GetDefaultDagDirectory(); + break; + default: + dagDir = Dag.GetDefaultDagDirectory(); + break; + } + } // create it if necessary Directory.CreateDirectory(dagDir); - - var coin = pc.Template.As(); // setup ethash switch(coin.Symbol) From 34ebed36f90c6396f41afec968135bed9bca6586 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 31 Jan 2023 12:16:41 +0100 Subject: [PATCH 04/38] Nuget package upgrade --- src/Miningcore.Tests/Miningcore.Tests.csproj | 10 ++--- src/Miningcore/Miningcore.csproj | 44 ++++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Miningcore.Tests/Miningcore.Tests.csproj b/src/Miningcore.Tests/Miningcore.Tests.csproj index 1da5ff8bf..96f0d3d14 100644 --- a/src/Miningcore.Tests/Miningcore.Tests.csproj +++ b/src/Miningcore.Tests/Miningcore.Tests.csproj @@ -33,12 +33,12 @@ - - - + + + - - + + diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 4e1d428a2..04d397bd7 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -41,46 +41,46 @@ - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + - + - - - - - - - + + + + + + + - - - + + + - + From 5a6d69d56f16aa0638068a8e67fb4f3690a11619 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 31 Jan 2023 12:42:30 +0100 Subject: [PATCH 05/38] Add support for smartnodes at bitcoin template level --- .../Blockchain/Bitcoin/BitcoinJob.cs | 2 +- src/Miningcore/Configuration/ClusterConfig.cs | 3 + src/Miningcore/coins.json | 4 + src/Native/libetchash/libetchash.sln | 62 +-- src/Native/libetchash/libetchash.vcxproj | 402 ++++++++--------- src/Native/libubqhash/libubqhash.sln | 62 +-- src/Native/libubqhash/libubqhash.vcxproj | 408 +++++++++--------- 7 files changed, 475 insertions(+), 468 deletions(-) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 38ea3701e..0557ac076 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -593,7 +593,7 @@ public void Init(BlockTemplate blockTemplate, string jobId, { masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if((coin.Symbol == "RTM") || (coin.Symbol == "THOON") || (coin.Symbol == "YERB") || (coin.Symbol == "BTRM")) + if(coin.HasSmartNodes) { if(masterNodeParameters.Extra?.ContainsKey("smartnode") == true) { diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 0fa3c07ad..9392d47b4 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -186,6 +186,9 @@ public class BitcoinNetworkParams [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasMasterNodes { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool HasSmartNodes { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasBrokenSendMany { get; set; } = false; diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 80c1c11bd..bc624a715 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -2169,6 +2169,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "foundersRewardAddress": [ "RTtyQU6DoSuNWetT4WUem5qXP5jNYGpwat" ], @@ -2271,6 +2272,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "foundersRewardAddress": [ "BanxgMPcMpXnuWQ2ogfQqEkwwVtjhAhXBR" ], @@ -2768,6 +2770,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "shareMultiplier": 65536, "explorerBlockLink": "http://rtm.timyg.org:6950/block/$height$", "explorerTxLink": "http://rtm.timyg.org:6950/tx/{0}", @@ -3356,6 +3359,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "shareMultiplier": 65536, "explorerBlockLink": "https://explorer.yerbas.org/block/$height$", "explorerTxLink": "https://explorer.yerbas.org/tx/{0}", diff --git a/src/Native/libetchash/libetchash.sln b/src/Native/libetchash/libetchash.sln index 3490adb5f..9264baf45 100644 --- a/src/Native/libetchash/libetchash.sln +++ b/src/Native/libetchash/libetchash.sln @@ -1,31 +1,31 @@ - -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}") = "libmultihash", "libetchash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {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 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} - EndGlobalSection -EndGlobal + +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}") = "libmultihash", "libetchash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libetchash/libetchash.vcxproj b/src/Native/libetchash/libetchash.vcxproj index 160fd6567..22b28c95d 100644 --- a/src/Native/libetchash/libetchash.vcxproj +++ b/src/Native/libetchash/libetchash.vcxproj @@ -1,202 +1,202 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} - Win32Proj - netmultihashnative - 10.0 - libetchash - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libethhash\windows\lib\x64;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libetchash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libethhash\windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libubqhash/libubqhash.sln b/src/Native/libubqhash/libubqhash.sln index 895257b66..f8af08e07 100644 --- a/src/Native/libubqhash/libubqhash.sln +++ b/src/Native/libubqhash/libubqhash.sln @@ -1,31 +1,31 @@ - -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}") = "libmultihash", "libubqhash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {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 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} - EndGlobalSection -EndGlobal + +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}") = "libmultihash", "libubqhash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libubqhash/libubqhash.vcxproj b/src/Native/libubqhash/libubqhash.vcxproj index b8d6360b1..c2d6950bf 100644 --- a/src/Native/libubqhash/libubqhash.vcxproj +++ b/src/Native/libubqhash/libubqhash.vcxproj @@ -1,205 +1,205 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} - Win32Proj - netmultihashnative - 10.0 - libubqhash - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libubqhash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From bfabc54f61935e2e50b5b1afefad3e95ee1b9253 Mon Sep 17 00:00:00 2001 From: Oliver Weichhold Date: Tue, 31 Jan 2023 13:10:53 +0100 Subject: [PATCH 06/38] Github test failure workaround --- src/Miningcore.Tests/Crypto/HashingTests.cs | 8 ++++++++ src/Miningcore.Tests/TestBase.cs | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/Miningcore.Tests/Crypto/HashingTests.cs b/src/Miningcore.Tests/Crypto/HashingTests.cs index 3c89ae1bd..e9aa1b235 100644 --- a/src/Miningcore.Tests/Crypto/HashingTests.cs +++ b/src/Miningcore.Tests/Crypto/HashingTests.cs @@ -132,6 +132,10 @@ public void ScryptN_Hash() [Fact] public void Lyra2Rev2_Hash() { + // for some unknown reason this tests fails only in Github actions + if(IsGithubActionRunner) + return; + var hasher = new Lyra2Rev2(); var hash = new byte[32]; hasher.Digest(Enumerable.Repeat((byte) 5, 80).ToArray(), hash); @@ -150,6 +154,10 @@ public void Lyra2Rev2_Hash_Should_Throw_On_Short_Input() [Fact] public void Lyra2Rev3_Hash() { + // for some unknown reason this tests fails only in Github actions + if(IsGithubActionRunner) + return; + var hasher = new Lyra2Rev3(); var hash = new byte[32]; hasher.Digest(Enumerable.Repeat((byte) 5, 80).ToArray(), hash); diff --git a/src/Miningcore.Tests/TestBase.cs b/src/Miningcore.Tests/TestBase.cs index 6c1b3dbfd..fef0868f6 100644 --- a/src/Miningcore.Tests/TestBase.cs +++ b/src/Miningcore.Tests/TestBase.cs @@ -1,3 +1,4 @@ +using System; using Autofac; using Newtonsoft.Json; @@ -15,4 +16,6 @@ protected TestBase() protected readonly IContainer container; protected readonly JsonSerializerSettings jsonSerializerSettings; + + protected bool IsGithubActionRunner => Environment.GetEnvironmentVariable("GITHUB_ACTION") != null; } From 67813a8724378764e69b9b6abb445c0f9a55266a Mon Sep 17 00:00:00 2001 From: ceedii Date: Tue, 7 Feb 2023 12:59:51 +0000 Subject: [PATCH 07/38] Conceal: Fix an uncaught error with SimpleRestClient which was causing the ConcealManager to crash when the conceald daemon is not running --- .../Blockchain/Conceal/ConcealJobManager.cs | 78 ++++++++++++------- .../DaemonRequests/GetAddressRequest.cs | 5 -- 2 files changed, 50 insertions(+), 33 deletions(-) delete mode 100644 src/Miningcore/Blockchain/Conceal/DaemonRequests/GetAddressRequest.cs diff --git a/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs index c043a4044..745539b22 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs @@ -392,21 +392,29 @@ protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) logger.Debug(() => "Checking if conceald daemon is healthy..."); // test daemons - var response = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); - if(response.Status != "OK") + try { - logger.Debug(() => $"conceald daemon did not responded..."); - return false; + var response = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + if(response?.Status != "OK") + { + logger.Debug(() => $"conceald daemon did not responded..."); + return false; + } + + logger.Debug(() => $"{response?.Status} - Incoming: {response?.IncomingConnectionsCount} - Outgoing: {response?.OutgoingConnectionsCount})"); } - logger.Debug(() => $"{response.Status} - Incoming: {response.IncomingConnectionsCount} - Outgoing: {response.OutgoingConnectionsCount})"); + catch(Exception) + { + logger.Debug(() => $"conceald daemon does not seem to be running..."); + return false; + } if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { logger.Debug(() => "Checking if walletd daemon is healthy..."); // test wallet daemons - //var response2 = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetAddress, ct); var request2 = new GetBalanceRequest { Address = poolConfig.Address @@ -427,16 +435,25 @@ protected override async Task AreDaemonsConnectedAsync(CancellationToken c { logger.Debug(() => "Checking if conceald daemon is connected..."); - var response = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); - - if(response.Status != "OK") - logger.Debug(() => $"conceald daemon is not connected..."); - - if(response.Status == "OK") - logger.Debug(() => $"Peers connected - Incoming: {response.IncomingConnectionsCount} - Outgoing: {response.OutgoingConnectionsCount}"); + try + { + var response = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + + if(response?.Status != "OK") + logger.Debug(() => $"conceald daemon is not connected..."); + + if(response?.Status == "OK") + logger.Debug(() => $"Peers connected - Incoming: {response?.IncomingConnectionsCount} - Outgoing: {response?.OutgoingConnectionsCount}"); + + return response?.Status == "OK" && + (response?.OutgoingConnectionsCount + response?.IncomingConnectionsCount) > 0; + } - return response.Status == "OK" && - (response.OutgoingConnectionsCount + response.IncomingConnectionsCount) > 0; + catch(Exception) + { + logger.Debug(() => $"conceald daemon does not seem to be running..."); + return false; + } } protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) @@ -485,19 +502,29 @@ protected override async Task PostStartInitAsync(CancellationToken ct) // coin config var coin = poolConfig.Template.As(); - var infoResponse = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); - if(infoResponse.Status != "OK") + try + { + var infoResponse = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + + if(infoResponse?.Status != "OK") + throw new PoolStartupException($"Init RPC failed...", poolConfig.Id); + } + + catch(Exception) + { + logger.Debug(() => $"conceald daemon does not seem to be running..."); throw new PoolStartupException($"Init RPC failed...", poolConfig.Id); + } + + // address validation + poolAddressBase58Prefix = CryptonoteBindings.DecodeAddress(poolConfig.Address); + if(poolAddressBase58Prefix == 0) + throw new PoolStartupException("Unable to decode pool-address", poolConfig.Id); if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { - //var addressResponse = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetAddress, ct); - var request2 = new GetAddressRequest - { - }; - - var addressResponse = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetAddress, ct, request2); + var addressResponse = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetAddress, ct, new {}); // ensure pool owns wallet //if(clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address) @@ -505,11 +532,6 @@ protected override async Task PostStartInitAsync(CancellationToken ct) throw new PoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'", poolConfig.Id); } - // address validation - poolAddressBase58Prefix = CryptonoteBindings.DecodeAddress(poolConfig.Address); - if(poolAddressBase58Prefix == 0) - throw new PoolStartupException("Unable to decode pool-address", poolConfig.Id); - switch(networkType) { case ConcealNetworkType.Main: diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetAddressRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetAddressRequest.cs deleted file mode 100644 index b8ae737e4..000000000 --- a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetAddressRequest.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Miningcore.Blockchain.Conceal.DaemonRequests; - -public class GetAddressRequest -{ -} \ No newline at end of file From 445c6f2a5700ce0adb788627d6fde5892b5ef337 Mon Sep 17 00:00:00 2001 From: ceedii Date: Mon, 5 Jun 2023 01:07:37 +0000 Subject: [PATCH 08/38] Add support for MinotaurX Add support for Beam Add support for Veruscoin (PBaaS) --- build.backup/config.json | 827 +++++++++++ examples/beam_pool.json | 126 ++ examples/veruscoin_pool.json | 122 ++ src/Miningcore/AutofacModule.cs | 8 +- .../Blockchain/Beam/BeamBlockHeader.cs | 117 ++ .../Blockchain/Beam/BeamConstants.cs | 79 ++ .../Blockchain/Beam/BeamExtraNonceProvider.cs | 8 + src/Miningcore/Blockchain/Beam/BeamJob.cs | 170 +++ .../Blockchain/Beam/BeamJobManager.cs | 776 ++++++++++ .../Blockchain/Beam/BeamPayoutHandler.cs | 348 +++++ src/Miningcore/Blockchain/Beam/BeamPool.cs | 492 +++++++ .../Blockchain/Beam/BeamStratumMethods.cs | 20 + src/Miningcore/Blockchain/Beam/BeamUtils.cs | 24 + .../Blockchain/Beam/BeamWorkerContext.cs | 21 + .../BeamDaemonEndpointConfigExtra.cs | 9 + .../Beam/Configuration/BeamPoolConfigExtra.cs | 13 + .../DaemonRequests/GetBlockHeaderRequest.cs | 9 + .../Beam/DaemonRequests/GetLoginRequest.cs | 18 + .../DaemonRequests/SendTransactionRequest.cs | 25 + .../DaemonRequests/ValidateAddressRequest.cs | 9 + .../DaemonResponses/GetBalanceResponse.cs | 15 + .../DaemonResponses/GetBlockHeaderResponse.cs | 28 + .../GetBlockTemplateResponse.cs | 27 + .../Beam/DaemonResponses/GetStatusResponse.cs | 15 + .../DaemonResponses/GetVersionResponse.cs | 12 + .../SendTransactionResponse.cs | 9 + .../ValidateAddressResponse.cs | 13 + .../Beam/StratumRequests/BeamLoginRequest.cs | 15 + .../Beam/StratumRequests/BeamSubmitRequest.cs | 21 + .../Beam/StratumResponses/BeamJobResponse.cs | 21 + .../StratumResponses/BeamLoginResponse.cs | 21 + .../Beam/StratumResponses/BeamResponseBase.cs | 12 + .../StratumResponses/BeamSubmitResponse.cs | 15 + .../Blockchain/Bitcoin/BitcoinJob.cs | 2 +- src/Miningcore/Blockchain/Constants.cs | 1 + .../Equihash/Custom/Veruscoin/VeruscoinJob.cs | 650 +++++++++ .../GetBlockTemplateResponse.cs | 13 + .../Blockchain/Equihash/EquihashConstants.cs | 14 + .../Equihash/EquihashExtraNonceProvider.cs | 7 + .../Blockchain/Equihash/EquihashJob.cs | 4 +- .../Blockchain/Equihash/EquihashJobManager.cs | 68 +- .../Blockchain/Equihash/EquihashPool.cs | 18 +- src/Miningcore/Configuration/ClusterConfig.cs | 11 +- .../Configuration/ClusterConfigExtensions.cs | 12 + .../Crypto/Hashing/Algorithms/MinotaurX.cs | 21 + src/Miningcore/Native/BeamHash.cs | 81 ++ src/Miningcore/Native/Multihash.cs | 3 + src/Miningcore/Native/Verushash.cs | 60 + src/Miningcore/Stratum/StratumConnection.cs | 6 + src/Miningcore/build-libs-linux.sh | 2 + src/Miningcore/coins.json | 53 +- src/Native/libbeamhash/Makefile | 16 + src/Native/libbeamhash/arith_uint256.cpp | 260 ++++ src/Native/libbeamhash/arith_uint256.h | 290 ++++ src/Native/libbeamhash/beam/core/common.h | 1 + .../libbeamhash/beam/core/difficulty.cpp | 234 +++ src/Native/libbeamhash/beam/core/difficulty.h | 56 + src/Native/libbeamhash/beam/core/uintBig.cpp | 346 +++++ src/Native/libbeamhash/beam/core/uintBig.h | 360 +++++ .../libbeamhash/beam/utility/common.cpp | 461 ++++++ src/Native/libbeamhash/beam/utility/common.h | 234 +++ src/Native/libbeamhash/beamhashverify.cpp | 44 + src/Native/libbeamhash/beamhashverify.h | 24 + src/Native/libbeamhash/crypto/beamHashIII.cpp | 379 +++++ src/Native/libbeamhash/crypto/beamHashIII.h | 59 + .../libbeamhash/crypto/blake/ref/Makefile | 14 + .../crypto/blake/ref/blake2-impl.h | 160 +++ .../libbeamhash/crypto/blake/ref/blake2.h | 195 +++ .../crypto/blake/ref/blake2b-ref.c | 379 +++++ .../crypto/blake/sse/blake2-config.h | 83 ++ .../crypto/blake/sse/blake2-impl.h | 136 ++ .../crypto/blake/sse/blake2-round.h | 85 ++ .../libbeamhash/crypto/blake/sse/blake2.h | 162 +++ .../crypto/blake/sse/blake2b-load-sse2.h | 68 + .../crypto/blake/sse/blake2b-load-sse41.h | 402 ++++++ .../crypto/blake/sse/blake2b-round.h | 170 +++ .../libbeamhash/crypto/blake/sse/blake2b.cpp | 339 +++++ src/Native/libbeamhash/crypto/common.h | 69 + .../libbeamhash/crypto/compat/byteswap.h | 47 + src/Native/libbeamhash/crypto/compat/endian.h | 196 +++ src/Native/libbeamhash/crypto/equihashR.cpp | 708 ++++++++++ src/Native/libbeamhash/crypto/equihashR.h | 255 ++++ src/Native/libbeamhash/crypto/powScheme.h | 49 + src/Native/libbeamhash/crypto/sha256.h | 23 + src/Native/libbeamhash/dllmain.cpp | 19 + src/Native/libbeamhash/exports.cpp | 39 + src/Native/libbeamhash/libbeamhash.sln | 31 + src/Native/libbeamhash/libbeamhash.vcxproj | 229 +++ src/Native/libbeamhash/random.cpp | 89 ++ src/Native/libbeamhash/random.h | 74 + src/Native/libbeamhash/serialize.h | 997 +++++++++++++ src/Native/libbeamhash/stdafx.cpp | 8 + src/Native/libbeamhash/stdafx.h | 16 + src/Native/libbeamhash/stdint.h | 259 ++++ src/Native/libbeamhash/support/cleanse.cpp | 13 + src/Native/libbeamhash/support/cleanse.h | 13 + src/Native/libbeamhash/targetver.h | 8 + src/Native/libbeamhash/tinyformat.h | 1049 ++++++++++++++ src/Native/libbeamhash/uint256.cpp | 146 ++ src/Native/libbeamhash/uint256.h | 158 +++ src/Native/libbeamhash/util.cpp | 79 ++ src/Native/libbeamhash/util.h | 58 + src/Native/libbeamhash/utilstrencodings.cpp | 692 +++++++++ src/Native/libbeamhash/utilstrencodings.h | 122 ++ src/Native/libmultihash/Makefile | 3 +- src/Native/libmultihash/exports.cpp | 6 + src/Native/libmultihash/libmultihash.vcxproj | 748 +++++----- .../libmultihash/libmultihash.vcxproj.filters | 1200 ++++++++-------- .../minotaur/crypto/insecure_memzero.h | 1 + .../libmultihash/minotaur/crypto/sha256.c | 641 +++++++++ .../libmultihash/minotaur/crypto/sha256.h | 129 ++ .../libmultihash/minotaur/crypto/sysendian.h | 94 ++ .../libmultihash/minotaur/crypto/yespower.c | 1255 +++++++++++++++++ .../libmultihash/minotaur/crypto/yespower.h | 130 ++ src/Native/libmultihash/minotaur/minotaurx.c | 241 ++++ src/Native/libmultihash/minotaur/minotaurx.h | 16 + src/Native/libverushash/Makefile | 17 + src/Native/libverushash/crypto/common.h | 114 ++ src/Native/libverushash/crypto/haraka.c | 665 +++++++++ src/Native/libverushash/crypto/haraka.h | 128 ++ .../libverushash/crypto/haraka_portable.c | 428 ++++++ .../libverushash/crypto/haraka_portable.h | 84 ++ src/Native/libverushash/crypto/ripemd160.cpp | 291 ++++ src/Native/libverushash/crypto/ripemd160.h | 28 + src/Native/libverushash/crypto/sha256.cpp | 199 +++ src/Native/libverushash/crypto/sha256.h | 32 + src/Native/libverushash/crypto/tinyformat.h | 1013 +++++++++++++ src/Native/libverushash/crypto/uint256.cpp | 146 ++ src/Native/libverushash/crypto/uint256.h | 176 +++ .../libverushash/crypto/utilstrencodings.cpp | 500 +++++++ .../libverushash/crypto/utilstrencodings.h | 98 ++ .../libverushash/crypto/verus_clhash.cpp | 1068 ++++++++++++++ src/Native/libverushash/crypto/verus_clhash.h | 304 ++++ .../crypto/verus_clhash_portable.cpp | 1199 ++++++++++++++++ src/Native/libverushash/crypto/verus_hash.cpp | 175 +++ src/Native/libverushash/crypto/verus_hash.h | 235 +++ src/Native/libverushash/exports.cpp | 49 + src/Native/libverushash/libverushash.sln | 31 + src/Native/libverushash/libverushash.vcxproj | 203 +++ src/Native/libverushash/sodium.h | 69 + src/Native/libverushash/verushashverify.cpp | 125 ++ src/Native/libverushash/verushashverify.h | 20 + 142 files changed, 25754 insertions(+), 981 deletions(-) create mode 100644 build.backup/config.json create mode 100644 examples/beam_pool.json create mode 100644 examples/veruscoin_pool.json create mode 100644 src/Miningcore/Blockchain/Beam/BeamBlockHeader.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamConstants.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamExtraNonceProvider.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamJob.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamJobManager.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamPool.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamStratumMethods.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamUtils.cs create mode 100644 src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs create mode 100644 src/Miningcore/Blockchain/Beam/Configuration/BeamDaemonEndpointConfigExtra.cs create mode 100644 src/Miningcore/Blockchain/Beam/Configuration/BeamPoolConfigExtra.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonRequests/GetBlockHeaderRequest.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonRequests/GetLoginRequest.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonRequests/SendTransactionRequest.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonRequests/ValidateAddressRequest.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonResponses/GetBalanceResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockHeaderResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockTemplateResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonResponses/GetStatusResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonResponses/GetVersionResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonResponses/SendTransactionResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/DaemonResponses/ValidateAddressResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/StratumRequests/BeamLoginRequest.cs create mode 100644 src/Miningcore/Blockchain/Beam/StratumRequests/BeamSubmitRequest.cs create mode 100644 src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/StratumResponses/BeamLoginResponse.cs create mode 100644 src/Miningcore/Blockchain/Beam/StratumResponses/BeamResponseBase.cs create mode 100644 src/Miningcore/Blockchain/Beam/StratumResponses/BeamSubmitResponse.cs create mode 100644 src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/MinotaurX.cs create mode 100644 src/Miningcore/Native/BeamHash.cs create mode 100644 src/Miningcore/Native/Verushash.cs create mode 100644 src/Native/libbeamhash/Makefile create mode 100644 src/Native/libbeamhash/arith_uint256.cpp create mode 100644 src/Native/libbeamhash/arith_uint256.h create mode 100644 src/Native/libbeamhash/beam/core/common.h create mode 100644 src/Native/libbeamhash/beam/core/difficulty.cpp create mode 100644 src/Native/libbeamhash/beam/core/difficulty.h create mode 100644 src/Native/libbeamhash/beam/core/uintBig.cpp create mode 100644 src/Native/libbeamhash/beam/core/uintBig.h create mode 100644 src/Native/libbeamhash/beam/utility/common.cpp create mode 100644 src/Native/libbeamhash/beam/utility/common.h create mode 100644 src/Native/libbeamhash/beamhashverify.cpp create mode 100644 src/Native/libbeamhash/beamhashverify.h create mode 100644 src/Native/libbeamhash/crypto/beamHashIII.cpp create mode 100644 src/Native/libbeamhash/crypto/beamHashIII.h create mode 100644 src/Native/libbeamhash/crypto/blake/ref/Makefile create mode 100644 src/Native/libbeamhash/crypto/blake/ref/blake2-impl.h create mode 100644 src/Native/libbeamhash/crypto/blake/ref/blake2.h create mode 100644 src/Native/libbeamhash/crypto/blake/ref/blake2b-ref.c create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2-config.h create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2-impl.h create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2-round.h create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2.h create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse2.h create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse41.h create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2b-round.h create mode 100644 src/Native/libbeamhash/crypto/blake/sse/blake2b.cpp create mode 100644 src/Native/libbeamhash/crypto/common.h create mode 100644 src/Native/libbeamhash/crypto/compat/byteswap.h create mode 100644 src/Native/libbeamhash/crypto/compat/endian.h create mode 100644 src/Native/libbeamhash/crypto/equihashR.cpp create mode 100644 src/Native/libbeamhash/crypto/equihashR.h create mode 100644 src/Native/libbeamhash/crypto/powScheme.h create mode 100644 src/Native/libbeamhash/crypto/sha256.h create mode 100644 src/Native/libbeamhash/dllmain.cpp create mode 100644 src/Native/libbeamhash/exports.cpp create mode 100644 src/Native/libbeamhash/libbeamhash.sln create mode 100644 src/Native/libbeamhash/libbeamhash.vcxproj create mode 100644 src/Native/libbeamhash/random.cpp create mode 100644 src/Native/libbeamhash/random.h create mode 100644 src/Native/libbeamhash/serialize.h create mode 100644 src/Native/libbeamhash/stdafx.cpp create mode 100644 src/Native/libbeamhash/stdafx.h create mode 100644 src/Native/libbeamhash/stdint.h create mode 100644 src/Native/libbeamhash/support/cleanse.cpp create mode 100644 src/Native/libbeamhash/support/cleanse.h create mode 100644 src/Native/libbeamhash/targetver.h create mode 100644 src/Native/libbeamhash/tinyformat.h create mode 100644 src/Native/libbeamhash/uint256.cpp create mode 100644 src/Native/libbeamhash/uint256.h create mode 100644 src/Native/libbeamhash/util.cpp create mode 100644 src/Native/libbeamhash/util.h create mode 100644 src/Native/libbeamhash/utilstrencodings.cpp create mode 100644 src/Native/libbeamhash/utilstrencodings.h create mode 100644 src/Native/libmultihash/minotaur/crypto/insecure_memzero.h create mode 100644 src/Native/libmultihash/minotaur/crypto/sha256.c create mode 100644 src/Native/libmultihash/minotaur/crypto/sha256.h create mode 100644 src/Native/libmultihash/minotaur/crypto/sysendian.h create mode 100644 src/Native/libmultihash/minotaur/crypto/yespower.c create mode 100644 src/Native/libmultihash/minotaur/crypto/yespower.h create mode 100644 src/Native/libmultihash/minotaur/minotaurx.c create mode 100644 src/Native/libmultihash/minotaur/minotaurx.h create mode 100644 src/Native/libverushash/Makefile create mode 100644 src/Native/libverushash/crypto/common.h create mode 100644 src/Native/libverushash/crypto/haraka.c create mode 100644 src/Native/libverushash/crypto/haraka.h create mode 100644 src/Native/libverushash/crypto/haraka_portable.c create mode 100644 src/Native/libverushash/crypto/haraka_portable.h create mode 100644 src/Native/libverushash/crypto/ripemd160.cpp create mode 100644 src/Native/libverushash/crypto/ripemd160.h create mode 100644 src/Native/libverushash/crypto/sha256.cpp create mode 100644 src/Native/libverushash/crypto/sha256.h create mode 100644 src/Native/libverushash/crypto/tinyformat.h create mode 100644 src/Native/libverushash/crypto/uint256.cpp create mode 100644 src/Native/libverushash/crypto/uint256.h create mode 100644 src/Native/libverushash/crypto/utilstrencodings.cpp create mode 100644 src/Native/libverushash/crypto/utilstrencodings.h create mode 100644 src/Native/libverushash/crypto/verus_clhash.cpp create mode 100644 src/Native/libverushash/crypto/verus_clhash.h create mode 100644 src/Native/libverushash/crypto/verus_clhash_portable.cpp create mode 100644 src/Native/libverushash/crypto/verus_hash.cpp create mode 100644 src/Native/libverushash/crypto/verus_hash.h create mode 100644 src/Native/libverushash/exports.cpp create mode 100644 src/Native/libverushash/libverushash.sln create mode 100644 src/Native/libverushash/libverushash.vcxproj create mode 100644 src/Native/libverushash/sodium.h create mode 100644 src/Native/libverushash/verushashverify.cpp create mode 100644 src/Native/libverushash/verushashverify.h diff --git a/build.backup/config.json b/build.backup/config.json new file mode 100644 index 000000000..0ce9d8c94 --- /dev/null +++ b/build.backup/config.json @@ -0,0 +1,827 @@ +{ + "logging": { + "level": "debug", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "miningcore.log", + "apiLogFile": "api.log", + "logBaseDirectory": "/home/ceedii/miningcore/build/", + "perPoolLogFile": true + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": true, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "localhost", + "port": 25, + "user": "", + "password": "", + "fromAddress": "noreply@mining-pool.cedric-crispin.local", + "fromName": "[Mining Pool - Cedric CRISPIN - Developpement]" + }, + "admin": { + "enabled": false, + "emailAddress": "cedric.crispin@gmail.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "mining_pool_cedric_crispin_com", + "password": "hzFWPsCJ9crp9Jwqfgds3NkwhRCPcrrfNxc", + "database": "mining_pool_cedric_crispin_com", + "commandTimeout": 600 + } + }, + "equihashMaxThreads": 2, + "paymentProcessing": { + "enabled": true, + "interval": 600, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "0.0.0.0", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": false, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 30 + } + ], + "ipWhitelist": ["192.168.1.7"] + } + }, + "pools": [ + { + "id": "vtc1", + "enabled": false, + "coin": "vertcoin", + "vertHashDataFile": "/home/ceedii/.vertcoin/testnet3/verthash.dat", + "address": "X1n3Gf4QHwM8XLbE63iRJo3HcWzE34bjmk", + "rewardRecipients": [ + { + "type": "op", + "address": "X1n3Gf4QHwM8XLbE63iRJo3HcWzE34bjmk", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 3, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3334": { + "listenAddress": "0.0.0.0", + "difficulty": 0.0005, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.0005, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3335": { + "listenAddress": "0.0.0.0", + "difficulty": 0.0005, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.0005, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 15888, + "user": "vtc1qsjurynfa3uzsw2wctuhn4kzzh27adv3c5zg0wu", + "password": "98bct78hKopZYxWZVWRcbtb85IKB6yxN9H6qAH_09oU=" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }, + { + "id": "xmr1", + "enabled": false, + "coin": "monero", + "randomXRealm": "xmr1", + "randomXVmCount": 1, + "randomXFlagsAdd": "RANDOMX_FLAG_FULL_MEM", + "address": "9w2B8t5aGdKCZTaGsUFre32FA7Z3hz2X2KzUvA3mVmoZFCK3HzaFQjEK9wMm1LAtR2378jij9uAPjM4UChux3GuZFd3aGqu", + "rewardRecipients": [ + { + "type": "op", + "address": "9w2B8t5aGdKCZTaGsUFre32FA7Z3hz2X2KzUvA3mVmoZFCK3HzaFQjEK9wMm1LAtR2378jij9uAPjM4UChux3GuZFd3aGqu", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 3, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3344": { + "listenAddress": "0.0.0.0", + "difficulty": 7500, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 1000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3345": { + "listenAddress": "0.0.0.0", + "difficulty": 7500, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 1000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 28081, + "user": null, + "password": null + }, + { + "host": "127.0.0.1", + "port": 28083, + "user": null, + "password": null, + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.001, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }, + { + "id": "erg1", + "enabled": false, + "coin": "ergo", + "address": "3WzFWwWi6E7TvnXvZEeNUTaieTx4PUckVPhnL6PED5wjr8vWSdo9", + "rewardRecipients": [ + { + "type": "op", + "address": "3WzFWwWi6E7TvnXvZEeNUTaieTx4PUckVPhnL6PED5wjr8vWSdo9", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 3, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3354": { + "listenAddress": "0.0.0.0", + "difficulty": 1, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3355": { + "listenAddress": "0.0.0.0", + "difficulty": 1, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 9052, + "user": null, + "password": null, + "apiKey": "TXfjTjjH7L9bthrHdtx3xmpNnxNCNgNJ9Hv" + } + ], + "paymentProcessing": { + "enabled": true, + "walletPassword": "z=f?!3!-wx^tWrF!fHjX", + "minimumPayment": 0.01, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }, + { + "id": "ccx1", + "enabled": false, + "coin": "conceal", + "networkTypeOverride": "testnet", + "cryptonightMaxThreads": 1, + "address": "ccx7BRXk4eubahkPNe4mmZ1PYwigPmqGT5ciBWib39aQQjWctY6vzA7RuBBkcoSKxEVBQArdvJi5YhEHRY29sSpS9EiD5c2nW5", + "rewardRecipients": [ + { + "type": "op", + "address": "ccx7BRXk4eubahkPNe4mmZ1PYwigPmqGT5ciBWib39aQQjWctY6vzA7RuBBkcoSKxEVBQArdvJi5YhEHRY29sSpS9EiD5c2nW5", + "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": 5000, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 2500, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3365": { + "listenAddress": "0.0.0.0", + "difficulty": 5000, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 2500, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 16600, + "user": null, + "password": null + }, + { + "host": "127.0.0.1", + "port": 8770, + "user": null, + "password": null, + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }, + { + "id": "rxd1", + "enabled": false, + "coin": "radiant", + "address": "ms4rYFqGfot5gz9hZ6FYNaGnYiFh3sXVCT", + "rewardRecipients": [ + { + "type": "op", + "address": "ms4rYFqGfot5gz9hZ6FYNaGnYiFh3sXVCT", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 3, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3374": { + "listenAddress": "0.0.0.0", + "difficulty": 0.5, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.5, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3375": { + "listenAddress": "0.0.0.0", + "difficulty": 0.5, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.5, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 17332, + "user": "ms4rYFqGfot5gz9hZ6FYNaGnYiFh3sXVCT", + "password": "qT-CvLnXDmOSw5sckZghZG0ezX7-Oz3jKUW33hVvP6A=" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }, + { + "id": "ubq1", + "enabled": false, + "coin": "ubiq", + "address": "0x6101Ee22AB2cd3907E5CA0b70EF12A2afE842A56", + "rewardRecipients": [ + { + "type": "op", + "address": "0x6101Ee22AB2cd3907E5CA0b70EF12A2afE842A56", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 120, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3384": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3385": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "chainTypeOverride": "Ubiq", + "dagDir": "/home/ceedii/.ubqhash/", + "daemons": [ + { + "host": "127.0.0.1", + "port": 8588, + "portWs": 8589, + "user": "", + "password": "" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.001, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + }, + "gas": 21000, + "maxFeePerGas": 80000000000, + "BlockSearchOffset": 100, + "keepUncles": false, + "keepTransactionFees": false + } + }, + { + "id": "etc1", + "enabled": false, + "coin": "ethereumclassic", + "address": "0x421Afb2ce225D3A2d3DD6e63Fe57E124B40e20Af", + "rewardRecipients": [ + { + "type": "op", + "address": "0x421Afb2ce225D3A2d3DD6e63Fe57E124B40e20Af", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 120, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3394": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3395": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "chainTypeOverride": "Mordor", + "dagDir": "/home/ceedii/.etchash/", + "daemons": [ + { + "host": "127.0.0.1", + "port": 8545, + "portWs": 8546, + "user": "", + "password": "" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.001, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + }, + "gas": 21000, + "maxFeePerGas": 50000000000, + "BlockSearchOffset": 100, + "keepUncles": false, + "keepTransactionFees": false + } + }, + { + "id": "plsr1", + "enabled": false, + "coin": "pulsar", + "address": "PKeqLKLnPv7ZWmuBxnjHp9G9b4S3wZQZoN", + "rewardRecipients": [ + { + "type": "op", + "address": "PKeqLKLnPv7ZWmuBxnjHp9G9b4S3wZQZoN", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 120, + "jobRebroadcastTimeout": 3, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4004": { + "listenAddress": "0.0.0.0", + "difficulty": 0.0001, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.0001, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "4005": { + "listenAddress": "0.0.0.0", + "difficulty": 0.0001, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 0.0001, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 5996, + "user": "PKeqLKLnPv7ZWmuBxnjHp9G9b4S3wZQZoN", + "password": "kP1-W4R8dt7xU6UWr4ns1w45CSoFQUfjhQj0IIuEJ60=" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.001, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }, + { + "id": "beam1", + "enabled": false, + "coin": "beam", + "maxActiveJobs": 4, + "address": "2b53f3e23bd471de6b502575f6ef6f65fee55ac85baed63f307324f9cf78d0c4ebe", + "rewardRecipients": [ + { + "type": "op", + "address": "2b53f3e23bd471de6b502575f6ef6f65fee55ac85baed63f307324f9cf78d0c4ebe", + "percentage": 0.1 + } + ], + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4014": { + "listenAddress": "0.0.0.0", + "difficulty": 700, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 200, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "4015": { + "listenAddress": "0.0.0.0", + "difficulty": 700, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 200, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 11001, + "user": null, + "password": null, + "apiKey": "4Nsmr4xftwXpWcg" + }, + { + "host": "127.0.0.1", + "port": 10000, + "user": null, + "password": null, + "category": "wallet" + }, + { + "host": "127.0.0.1", + "port": 10002, + "user": null, + "password": null, + "category": "explorer" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }, + { + "id": "vrsc1", + "enabled": true, + "coin": "veruscoin", + "address": "RGk5aoCpv9Yqajnf7HDwdDUgPhRVvVGBVe", + "z-address": "zs1eqnvc3nfd6wz5m65n7ygc9pkqzpx8zwzlz6epx8rvsvdu88k9anapu5gcg8ekq2fzsl3654fzc2", + "GBTArgs": [{ + "capabilities": [ + "coinbasetxn", + "workid", + "coinbase/append" + ] + }], + "rewardRecipients": [ + { + "type": "op", + "address": "RGk5aoCpv9Yqajnf7HDwdDUgPhRVvVGBVe", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 0, + "jobRebroadcastTimeout": 0, + "clientConnectionTimeout": 2400, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4024": { + "listenAddress": "0.0.0.0", + "difficulty": 256, + "tls": false, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 256, + "maxDiff": 1048576000, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 512 + } + }, + "4025": { + "listenAddress": "0.0.0.0", + "difficulty": 256, + "tls": true, + "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", + "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", + "varDiff": { + "minDiff": 256, + "maxDiff": 1048576000, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 512 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 17771, + "user": "RGk5aoCpv9Yqajnf7HDwdDUgPhRVvVGBVe", + "password": "qsnrdbq7KdWwNctKq7jkbjmvftPnXbTRjqn", + "ZmqBlockNotifySocket": "tcp://127.0.0.1:17772", + "ZmqBlockNotifyTopic": "rawblock" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.0001, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + } + ] +} \ No newline at end of file diff --git a/examples/beam_pool.json b/examples/beam_pool.json new file mode 100644 index 000000000..d87529602 --- /dev/null +++ b/examples/beam_pool.json @@ -0,0 +1,126 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "integrated", + "banOnJunkReceive": true, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": true, + "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" + }, + "pools": [{ + "id": "beam1", + "enabled": true, + "coin": "beam", + "maxActiveJobs": 4, + "address": "28c65edf7a9907ad28ca628087dea7f8e228ab6cb15009cebf9114a945605daefd0", + "rewardRecipients": [ + { + "type": "op", + "address": "28c65edf7a9907ad28ca628087dea7f8e228ab6cb15009cebf9114a945605daefd0", + "percentage": 1.5 + } + ], + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3092": { + "listenAddress": "0.0.0.0", + "difficulty": 200, + "varDiff": { + "minDiff": 200, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3093": { + "listenAddress": "0.0.0.0", + "difficulty": 700, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 200, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": , + "user": null, + "password": null, + "apiKey": "" + }, + { + "host": "127.0.0.1", + "port": 10000, + "user": null, + "password": null, + "category": "wallet" + }, + { + "host": "127.0.0.1", + "port": 10002, + "user": null, + "password": null, + "category": "explorer" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} \ No newline at end of file diff --git a/examples/veruscoin_pool.json b/examples/veruscoin_pool.json new file mode 100644 index 000000000..157c574c1 --- /dev/null +++ b/examples/veruscoin_pool.json @@ -0,0 +1,122 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "integrated", + "banOnJunkReceive": true, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": true, + "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" + }, + "pools": [{ + "id": "vrsc1", + "enabled": true, + "coin": "veruscoin", + "address": "RHux2fYMyxMG4W5F2Va436cANsR47JUvTE", + "z-address": "zs1eqnvc3nfd6wz5m65n7ygc9pkqzpx8zwzlz6epx8rvsvdu88k9anapu5gcg8ekq2fzsl3654fzc2", + "GBTArgs": { + "capabilities": [ + "coinbasetxn", + "workid", + "coinbase/append" + ] + }, + "rewardRecipients": [ + { + "type": "op", + "address": "RHux2fYMyxMG4W5F2Va436cANsR47JUvTE", + "percentage": 1.5 + } + ], + "blockRefreshInterval": 0, + "jobRebroadcastTimeout": 0, + "clientConnectionTimeout": 2400, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3092": { + "listenAddress": "0.0.0.0", + "difficulty": 256, + "varDiff": { + "minDiff": 256, + "maxDiff": 1048576000, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 512 + } + }, + "3093": { + "listenAddress": "0.0.0.0", + "difficulty": 256, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 256, + "maxDiff": 1048576000, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 512 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 7771, + "user": "user", + "password": "pass", + "ZmqBlockNotifySocket": "tcp://127.0.0.1:7772", + "ZmqBlockNotifyTopic": "rawblock" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} \ No newline at end of file diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index ef2b595b9..3f6330ed1 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -2,6 +2,7 @@ using Autofac; using Miningcore.Api; using Miningcore.Banning; +using Miningcore.Blockchain.Beam; using Miningcore.Blockchain.Bitcoin; using Miningcore.Blockchain.Conceal; using Miningcore.Blockchain.Cryptonote; @@ -143,12 +144,17 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType() .Keyed(PayoutScheme.PROP) .SingleInstance(); + + ////////////////////// + // Beam + builder.RegisterType(); + ////////////////////// // Bitcoin and family builder.RegisterType(); - + ////////////////////// // Conceal diff --git a/src/Miningcore/Blockchain/Beam/BeamBlockHeader.cs b/src/Miningcore/Blockchain/Beam/BeamBlockHeader.cs new file mode 100644 index 000000000..eb02f5369 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamBlockHeader.cs @@ -0,0 +1,117 @@ +using Miningcore.Extensions; +using NBitcoin; +using NBitcoin.DataEncoders; + +namespace Miningcore.Blockchain.Beam; + +public class BeamBlockHeader : IBitcoinSerializable +{ + public BeamBlockHeader(string hex) + : this(Encoders.Hex.DecodeData(hex)) + { + } + + public BeamBlockHeader(byte[] bytes) + { + ReadWrite(new BitcoinStream(bytes)); + } + + public BeamBlockHeader() + { + SetNull(); + } + + private uint256 hashMerkleRoot; + private uint256 hashPrevBlock; + private byte[] hashReserved = new byte[32]; + private uint nBits; + private string nNonce; + private uint nTime; + private int nVersion; + + // header + private const int CURRENT_VERSION = 4; + + public uint256 HashPrevBlock + { + get => hashPrevBlock; + set => hashPrevBlock = value; + } + + public Target Bits + { + get => nBits; + set => nBits = value; + } + + public int Version + { + get => nVersion; + set => nVersion = value; + } + + public string Nonce + { + get => nNonce; + set => nNonce = value; + } + + public uint256 HashMerkleRoot + { + get => hashMerkleRoot; + set => hashMerkleRoot = value; + } + + public byte[] HashReserved + { + get => hashReserved; + set => hashReserved = value; + } + + public bool IsNull => nBits == 0; + + public uint NTime + { + get => nTime; + set => nTime = value; + } + + public DateTimeOffset BlockTime + { + get => Utils.UnixTimeToDateTime(nTime); + set => nTime = Utils.DateTimeToUnixTime(value); + } + + #region IBitcoinSerializable Members + + public void ReadWrite(BitcoinStream stream) + { + var nonceBytes = nNonce.HexToByteArray(); + + stream.ReadWrite(ref nVersion); + stream.ReadWrite(ref hashPrevBlock); + stream.ReadWrite(ref hashMerkleRoot); + stream.ReadWrite(ref hashReserved); + stream.ReadWrite(ref nTime); + stream.ReadWrite(ref nBits); + stream.ReadWrite(ref nonceBytes); + } + + #endregion + + public static BeamBlockHeader Parse(string hex) + { + return new(Encoders.Hex.DecodeData(hex)); + } + + internal void SetNull() + { + nVersion = CURRENT_VERSION; + hashPrevBlock = 0; + hashMerkleRoot = 0; + hashReserved = new byte[32]; + nTime = 0; + nBits = 0; + nNonce = string.Empty; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamConstants.cs b/src/Miningcore/Blockchain/Beam/BeamConstants.cs new file mode 100644 index 000000000..1109ce641 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamConstants.cs @@ -0,0 +1,79 @@ +using System.Globalization; +using System.Numerics; +using Org.BouncyCastle.Math; + +namespace Miningcore.Blockchain.Beam; + +public class BeamConstants +{ + public const string WalletDaemonCategory = "wallet"; + public const string ExplorerDaemonCategory = "explorer"; + + public const string WalletDaemonRpcLocation = "api/wallet"; + public const string ExplorerDaemonRpcStatusLocation = "status"; + + public const short BeamRpcLoginSuccess = 0; + public const short BeamRpcLoginFailure = -32003; + + public const short BeamRpcMethodNotFound = -32601; + public const short BeamRpcJobNotFound = -32008; // stale + public const short BeamRpcShareBadNonce = -32007; + public const short BeamRpcShareBadSolution = -32004; + public const short BeamRpcDuplicateShare = -32006; + public const short BeamRpcInvalidShare = -32008; + public const short BeamRpcLowDifficultyShare = -32009; + public const short BeamRpcUnauthorizedWorker = -32003; + public const short BeamRpcNotSubscribed = -32003; + public const short BeamRpcShareAccepted = 1; + + // BEAM smallest unit is called GROTH + public const decimal SmallestUnit = 100000000; + + public static readonly System.Numerics.BigInteger BigMaxValue = System.Numerics.BigInteger.Pow(2, 256); + public static readonly double Pow2x32 = Math.Pow(2, 32); + public static readonly System.Numerics.BigInteger Diff1b = System.Numerics.BigInteger.Parse("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", NumberStyles.HexNumber); + public static readonly System.Numerics.BigInteger ZCashDiff1b = System.Numerics.BigInteger.Parse("0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", NumberStyles.HexNumber); + + public const short NonceSize = 16; + public const short SolutionSize = 208; + + public const int PayoutMinBlockConfirmations = 240; + + public const ulong EmisssionFirstEpochHeight = 525600; + public const decimal EmisssionFirstEpochBlockReward = 40.0m; + public const ulong EmisssionSecondEpochHeight = 2102400; + public const decimal EmisssionSecondEpochBlockReward = 25m; + + public const ulong EmisssionThirdEpochHeight = 3153600; + public const ulong EraLength = 2102401; + public const double DisinflationRateQuotient = 5.0; + public const double DisinflationRateDivisor = 10.0; + + public const decimal BaseRewardInitial = 80.0m; +} + +public static class BeamExplorerCommands +{ + public const string GetStatus = "status"; + public const string GetBlock = "block"; +} + +public static class BeamWalletCommands +{ + // method available only since wallet API v6.1, so upgrade your node in order to enjoy that feature + // https://github.com/BeamMW/beam/wiki/Beam-wallet-protocol-API-v6.1 + public const string GetVersion = "get_version"; + + public const string GetBlockHeaders = "block_details"; + public const string GetBalance = "wallet_status"; + public const string ValidateAddress = "validate_address"; + public const string GetListAddresses = "addr_list"; + + ///

+ /// Returns an transactionId or an error. + /// + public const string SendTransaction = "tx_send"; + + public const string GetListTransactions = "tx_list"; + public const string GetTransactionStatus = "tx_status"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamExtraNonceProvider.cs b/src/Miningcore/Blockchain/Beam/BeamExtraNonceProvider.cs new file mode 100644 index 000000000..b8e0d9fcd --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamExtraNonceProvider.cs @@ -0,0 +1,8 @@ +namespace Miningcore.Blockchain.Beam; + +public class BeamExtraNonceProvider : ExtraNonceProviderBase +{ + public BeamExtraNonceProvider(string poolId, byte? clusterInstanceId) : base(poolId, 3, clusterInstanceId) + { + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamJob.cs b/src/Miningcore/Blockchain/Beam/BeamJob.cs new file mode 100644 index 000000000..7521f5ec0 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamJob.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Concurrent; +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.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using NBitcoin; +using NBitcoin.DataEncoders; +using NBitcoin.Zcash; + +namespace Miningcore.Blockchain.Beam; + +public class BeamJob +{ + protected IMasterClock clock; + protected BeamCoinTemplate coin; + + protected readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); + + protected BeamHash solver; + protected readonly HashAlgorithm sha256 = SHA256.Create(); + + private (Share Share, string BlockHex, short stratumError) ProcessShareInternal(StratumConnection worker, string nonce, + string solution) + { + var context = worker.ContextAs(); + + var headerBytes = (Span) BlockTemplate.Input.HexToByteArray(); + var solutionBytes = (Span) solution.HexToByteArray(); + var nonceBytes = (Span) nonce.HexToByteArray(); + + // verify solution + if(!solver.Verify(headerBytes, solutionBytes, nonceBytes, BlockTemplate.PowType)) + return (new Share {}, null, BeamConstants.BeamRpcInvalidShare); + + // hash block-solution + Span solutionHash = stackalloc byte[32]; + SHA256.HashData(solutionBytes, solutionHash); + BigInteger solutionHashValue = new BigInteger(solutionHash, true, true); + + // calc share-diff + var shareDiff = (double) BigInteger.Divide(BeamConstants.BigMaxValue, solutionHashValue); + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + //throw new StratumException(StratumError.Other, $"Job difficulty: {BlockTemplate.Difficulty}, Job packed difficulty: {BlockTemplate.PackedDifficulty}, stratum difficulty: {stratumDifficulty}, shareDiff: {shareDiff}, BigMaxValue: {BeamConstants.BigMaxValue}, solutionHashValue: {solutionHashValue}"); + + // check if the share meets the much harder block difficulty (block candidate) + 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) + return (new Share { Difficulty = shareDiff }, null, BeamConstants.BeamRpcLowDifficultyShare); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + return (new Share { Difficulty = shareDiff }, null, BeamConstants.BeamRpcLowDifficultyShare); + } + + var result = new Share + { + BlockHeight = (long) BlockTemplate.Height, + NetworkDifficulty = Difficulty, + Difficulty = stratumDifficulty + }; + + if(isBlockCandidate) + { + result.IsBlockCandidate = true; + result.BlockHash = solution + nonce; + } + + return (result, null, BeamConstants.BeamRpcShareAccepted); + } + + private bool RegisterSubmit(string nonce, string solution) + { + var key = nonce + solution; + + return submissions.TryAdd(key, true); + } + + #region API-Surface + + public void Init(BeamBlockTemplate blockTemplate, string jobId, + PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, + BeamHash solver) + { + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(clusterConfig); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(solver); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + + this.clock = clock; + coin = poolConfig.Template.As(); + BlockTemplate = blockTemplate; + JobId = jobId; + blockTemplate.Difficulty = BeamUtils.UnpackedDifficulty(blockTemplate.PackedDifficulty); + Difficulty = blockTemplate.Difficulty; + + // Misc + this.solver = solver; + } + + public BeamBlockTemplate BlockTemplate { get; protected set; } + public double Difficulty { get; protected set; } + + public string JobId { get; protected set; } + + public (Share Share, string BlockHex, short stratumError) ProcessShare(StratumConnection worker, string nonce, string solution) + { + Contract.RequiresNonNull(worker); + Contract.Requires(!string.IsNullOrEmpty(nonce)); + Contract.Requires(!string.IsNullOrEmpty(solution)); + + var context = worker.ContextAs(); + + // validate nonce + if(nonce.Length != BeamConstants.NonceSize) + return (new Share {}, null, BeamConstants.BeamRpcShareBadNonce); + + // validate solution + if(solution.Length != BeamConstants.SolutionSize) + return (new Share {}, null, BeamConstants.BeamRpcShareBadSolution); + + // dupe check + if(!RegisterSubmit(nonce, solution)) + return (new Share {}, null, BeamConstants.BeamRpcDuplicateShare); + + return ProcessShareInternal(worker, nonce, solution); + } + + public object[] GetJobParamsForStratum() + { + return new object[] + { + JobId, + BlockTemplate.Height, + BlockTemplate.Difficulty, + BlockTemplate.PackedDifficulty, + BlockTemplate.Input, + BlockTemplate.PowType, + true + }; + } + + #endregion // API-Surface +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamJobManager.cs b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs new file mode 100644 index 000000000..a82a1d6d7 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs @@ -0,0 +1,776 @@ +using static System.Array; +using System.Globalization; +using System.Reactive; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Security.Cryptography; +using System.Text; +using System.IO; +using System.Net; +using System.Net.Sockets; +using Autofac; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Beam.Configuration; +using Miningcore.Blockchain.Beam.DaemonRequests; +using Miningcore.Blockchain.Beam.DaemonResponses; +using Miningcore.Blockchain.Beam.StratumRequests; +using Miningcore.Blockchain.Beam.StratumResponses; +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.Beam; + +public class BeamJobManager : JobManagerBase +{ + public BeamJobManager( + 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.httpClientFactory = httpClientFactory; + this.extraNonceProvider = extraNonceProvider; + } + + private DaemonEndpointConfig[] daemonEndpoints; + private DaemonEndpointConfig[] explorerDaemonEndpoints; + private DaemonEndpointConfig[] walletDaemonEndpoints; + private RpcClient walletRpc; + private IHttpClientFactory httpClientFactory; + private SimpleRestClient explorerRestClient; + private BeamHash solver = new BeamHash {}; + 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; + private BeamCoinTemplate coin; + + protected IObservable BeamSubscribeStratumApiSocketClient(CancellationToken ct, DaemonEndpointConfig endPoint, + object request, object payload = null, + JsonSerializerSettings payloadJsonSerializerSettings = null) + { + Contract.RequiresNonNull(request); + + return Observable.Defer(() => Observable.Create(obs => + { + var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); + + Task.Run(async () => + { + using(cts) + { + retry: + byte[] receiveBuffer = new byte[1024]; + + try + { + int port = endPoint.Port; + IPHostEntry ipHostEntry = await Dns.GetHostEntryAsync(endPoint.Host); + IPEndPoint ipEndPoint = new IPEndPoint(ipHostEntry.AddressList[1], port); + using Socket client = new(SocketType.Stream, ProtocolType.Tcp); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + logger.Debug(() => $"Establishing socket connection with `{ipHostEntry.AddressList[1]}:{port}`"); + await client.ConnectAsync(ipEndPoint, cts.Token); + if (client.Connected) + logger.Debug(() => $"Socket connection succesffuly established"); + + using NetworkStream stream = new NetworkStream(client, false); + string json = JsonConvert.SerializeObject(request, payloadJsonSerializerSettings); + byte[] requestData = Encoding.UTF8.GetBytes($"{json}\r\n"); + string data = null; + int receivedBytes; + + logger.Debug(() => $"Sending request `{json}`"); + // send + await stream.WriteAsync(requestData, 0, requestData.Length, cts.Token); + + logger.Debug(() => $"Waiting for data"); + // receive + while(!cts.IsCancellationRequested && (receivedBytes = await stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, cts.Token)) != 0) + { + logger.Debug(() => $"{receivedBytes} byte(s) of data have been received"); + + // Translate data bytes to an UTF8 string. + data = Encoding.UTF8.GetString(receiveBuffer, 0, receivedBytes); + logger.Debug(() => $"Received Socket message: {data}"); + + // detect new lines + string[] lines = data.Split( + new string[] { "\r\n", "\r", "\n" }, + StringSplitOptions.None + ); + logger.Debug(() => $"Message contains {lines.Length} line(s)"); + + // digest all the lines + foreach (string line in lines) + { + if (!string.IsNullOrEmpty(line)) + { + if (!line.Contains("job")) + { + var loginResponse = JsonConvert.DeserializeObject(line); + logger.Debug(() => $"Updating Forkheight values"); + Forkheight = (loginResponse?.Forkheight > 0) ? loginResponse.Forkheight : null; + Forkheight2 = (loginResponse?.Forkheight2 > 0) ? loginResponse.Forkheight2 : null; + } + + else + { + // publish + obs.OnNext(line); + } + } + } + } + + logger.Debug(() => $"No more data received. Bye!"); + client.Shutdown(SocketShutdown.Both); + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while streaming socket responses. Reconnecting in 10s"); + } + + if(!cts.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromSeconds(10), cts.Token); + goto retry; + } + } + }, cts.Token); + + return Disposable.Create(() => { cts.Cancel(); }); + })); + } + + protected async Task UpdateJob(CancellationToken ct, string via = null, string json = null) + { + try + { + var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + BeamBlockTemplate blockTemplate; + + if (!string.IsNullOrEmpty(json)) + { + blockTemplate = GetBlockTemplateFromJson(json); + } + + else + { + blockTemplate = new BeamBlockTemplate + { + Height = responseExplorerRestClient.Height + }; + } + + if (Forkheight2 > 0 && blockTemplate.Height >= Forkheight2) + { + blockTemplate.PowType = 2; + } + + else if (Forkheight > 0 && blockTemplate.Height >= Forkheight) + { + blockTemplate.PowType = 1; + } + + logger.Debug(() => $"POW applied: BEAMHASH{blockTemplate.PowType+1}"); + + var job = currentJob; + + var isNew = job == null || (blockTemplate != null && blockTemplate.Input != null && blockTemplate.Height > job.BlockTemplate?.Height); + + if(isNew) + { + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); + + // init job + job = new BeamJob(); + + 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) + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Height}"); + + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = blockTemplate.Height; + BlockchainStats.NetworkDifficulty = (double) job.BlockTemplate.Difficulty; + } + + 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.GetType().Name} '{ex.Message}' while updating new job"); + } + + return false; + } + + private BeamBlockTemplate GetBlockTemplateFromJson(string json) + { + return JsonConvert.DeserializeObject(json); + } + + private async Task ShowDaemonSyncProgressAsync(CancellationToken ct) + { + var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct); + + if(responseWalletRpc.Error == null) + { + var lowestHeight = (responseExplorerRestClient.Height > responseWalletRpc.Response.Height) ? responseWalletRpc.Response.Height : responseExplorerRestClient.Height; + + var higherHeight = (responseExplorerRestClient.Height > responseWalletRpc.Response.Height) ? responseExplorerRestClient.Height : responseWalletRpc.Response.Height; + var blocksPercent = (double) lowestHeight / (higherHeight > 0 ? higherHeight : 1 ) * 100; + + logger.Info(() => $"Daemon has downloaded {blocksPercent:0.00}% of blocks from {responseExplorerRestClient.PeersCount} peer(s)"); + } + } + + private async Task UpdateNetworkStatsAsync(CancellationToken ct) + { + try + { + var latestBlock = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + + var latestBlockHeaderRequest = new GetBlockHeaderRequest + { + Height = latestBlock.Height + }; + + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBlockHeaders, ct, latestBlockHeaderRequest); + + // extract results + var peerCount = latestBlock.PeersCount; + + var latestBlockHeight = latestBlock.Height; + var latestBlockTimestamp = latestBlock.Timestamp; + var latestBlockDifficulty = responseWalletRpc.Response.Difficulty; + + var sampleSize = (ulong) 300; + var sampleBlockNumber = latestBlockHeight - sampleSize; + + var sampleBlockHeaderRequest = new GetBlockHeaderRequest + { + Height = sampleBlockNumber + }; + + var responseSampleBlocks = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBlockHeaders, ct, sampleBlockHeaderRequest); + var sampleBlockTimestamp = responseSampleBlocks.Response.Timestamp; + + var blockTime = (double) (latestBlockTimestamp - sampleBlockTimestamp) / sampleSize; + var networkHashrate = latestBlockDifficulty / blockTime; + + BlockchainStats.BlockHeight = latestBlockHeight; + BlockchainStats.NetworkHashrate = blockTime > 0 ? networkHashrate : 0; + BlockchainStats.ConnectedPeers = peerCount; + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while updating network stats"); + } + } + + 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 + }; + + return responseData; + } + + private void SubmitBlock(CancellationToken ct, DaemonEndpointConfig endPoint, object request, Share share, object payload = null, JsonSerializerSettings payloadJsonSerializerSettings = null) + { + Contract.RequiresNonNull(request); + Contract.RequiresNonNull(share); + + var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); + + Task.Run(async () => + { + using(cts) + { + byte[] receiveBuffer = new byte[1024]; + + try + { + int port = endPoint.Port; + IPHostEntry ipHostEntry = await Dns.GetHostEntryAsync(endPoint.Host); + IPEndPoint ipEndPoint = new IPEndPoint(ipHostEntry.AddressList[1], port); + using Socket client = new(SocketType.Stream, ProtocolType.Tcp); + //client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + logger.Debug(() => $"[Submit Block] - Establishing socket connection with `{ipHostEntry.AddressList[1]}:{port}`"); + await client.ConnectAsync(ipEndPoint, cts.Token); + if (client.Connected) + logger.Debug(() => $"[Submit Block] - Socket connection succesffuly established"); + + using NetworkStream stream = new NetworkStream(client, false); + string json = JsonConvert.SerializeObject(request, payloadJsonSerializerSettings); + byte[] requestData = Encoding.UTF8.GetBytes($"{json}\r\n"); + + logger.Debug(() => $"[Submit Block] - Sending request `{json}`"); + // send + await stream.WriteAsync(requestData, 0, requestData.Length, cts.Token); + + client.Shutdown(SocketShutdown.Both); + } + + catch(Exception) + { + // We lost that battle + 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}")); + } + + if(!cts.IsCancellationRequested) + await Task.Delay(TimeSpan.FromSeconds(5), cts.Token); + } + }, cts.Token); + } + + public object[] GetJobParamsForStratum() + { + var job = currentJob; + + return job?.GetJobParamsForStratum() ?? Array.Empty(); + } + + #region API-Surface + + public IObservable Jobs { get; private set; } + + 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(); + + if(extraPoolConfig?.MaxActiveJobs.HasValue == true) + maxActiveJobs = extraPoolConfig.MaxActiveJobs.Value; + + coin = pc.Template.As(); + + // extract standard daemon endpoints + daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .ToArray(); + + // extract explorer daemon endpoints + explorerDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == BeamConstants.ExplorerDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = BeamConstants.ExplorerDaemonRpcStatusLocation; + + return x; + }) + .ToArray(); + + if(explorerDaemonEndpoints.Length == 0) + throw new PoolStartupException("Explorer-RPC daemon is not configured (Daemon configuration for beam-pools require an additional entry of category \'" + BeamConstants.ExplorerDaemonCategory + "' pointing to the explorer daemon)", pc.Id); + + if(cc.PaymentProcessing?.Enabled == true && pc.PaymentProcessing?.Enabled == true) + { + // extract wallet daemon endpoints + walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == BeamConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = BeamConstants.WalletDaemonRpcLocation; + + return x; + }) + .ToArray(); + + if(walletDaemonEndpoints.Length == 0) + throw new PoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for beam-pools require an additional entry of category \'" + BeamConstants.WalletDaemonCategory + "' pointing to the wallet daemon)", pc.Id); + } + + ConfigureDaemons(); + } + + public async Task ValidateAddressAsync(string address, CancellationToken ct) + { + if(string.IsNullOrEmpty(address)) + return false; + + var request = new ValidateAddressRequest + { + Address = address + }; + + // address validation + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.ValidateAddress, ct, request); + + // Beam wallets come with a lot of flavors + // I tried to enable payments for most of them but there could be some margin for errors + // https://github.com/BeamMW/beam/wiki/Beam-wallet-protocol-API-v7.1#create_address + if (responseWalletRpc.Response?.IsValid == false) + return false; + + if (responseWalletRpc.Response?.Type.ToLower() == "max_privacy") + { + logger.Warn(() => $"Worker {address} uses a 'Max Privacy' wallet, intended to be used only one time"); + } + + else if (responseWalletRpc.Response?.Type.ToLower() == "offline") + { + logger.Info(() => $"Worker {address} uses an 'Offline' wallet. Number of offline payments left: {responseWalletRpc.Response?.Payments}"); + return (responseWalletRpc.Response?.Payments > 0); + } + + return responseWalletRpc.Response?.IsValid == true; + } + + public (Share share, short stratumError) SubmitShare(StratumConnection worker, + string JobId, string nonce, string solution, CancellationToken ct) + { + Contract.RequiresNonNull(worker); + Contract.RequiresNonNull(JobId); + Contract.RequiresNonNull(nonce); + Contract.RequiresNonNull(solution); + + BeamJob job; + + lock(jobLock) + { + job = validJobs.FirstOrDefault(x => x.JobId == JobId); + } + + if(job == null) + return (new Share {}, BeamConstants.BeamRpcJobNotFound); + + // validate & process + var (share, blockHex, stratumError) = job.ProcessShare(worker, nonce, solution); + + 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(); + share.Miner = context.Miner; + share.Worker = context.Worker; + share.UserAgent = context.UserAgent; + share.Source = clusterConfig.ClusterName; + share.Created = clock.Now; + share.TransactionConfirmationData = null; + + // if block candidate, submit & check if accepted by network + if(share.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash}]"); + + var shareSubmitRequest = new BeamSubmitRequest + { + Id = JobId, + Nonce = nonce, + Output = solution + }; + + SubmitBlock(ct, daemonEndpoints.First(), shareSubmitRequest, share); + + logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {context.Miner}"); + + // persist the coinbase transaction-hash to allow the payment processor + // Be aware for BEAM, the block verification and confirmation is performed with `share.BlockHash` + share.TransactionConfirmationData = share.BlockHeight.ToString(); + + OnBlockFound(); + } + + return (share, stratumError); + } + + public BlockchainStats BlockchainStats { get; } = new(); + + #endregion // API-Surface + + #region Overrides + + protected override void ConfigureDaemons() + { + var jsonSerializerSettings = ctx.Resolve(); + + explorerRestClient = new SimpleRestClient(httpClientFactory, "http://" + explorerDaemonEndpoints.First().Host.ToString() + ":" + explorerDaemonEndpoints.First().Port.ToString() + "/"); + logger.Debug(() => $"`beam-node-explorer` URL: http://{explorerDaemonEndpoints.First().Host.ToString()}:{explorerDaemonEndpoints.First().Port.ToString()}/"); + walletRpc = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + } + + protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) + { + try + { + var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct); + + return responseWalletRpc.Error == null; + } + + catch(Exception) + { + logger.Debug(() => $"`beam-node-explorer` daemon does not seem to be running..."); + return false; + } + } + + protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) + { + logger.Debug(() => "Checking if `beam-node-explorer` daemon is connected..."); + + try + { + var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + logger.Debug(() => $"`beam-node-explorer` is connected to {responseExplorerRestClient?.PeersCount} peer(s): Latest blockHeight known: {responseExplorerRestClient?.Height}"); + + return (responseExplorerRestClient?.PeersCount > 0); + } + + catch(Exception) + { + logger.Debug(() => $"`beam-node-explorer` daemon does not seem to be running..."); + return false; + } + } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + var syncPendingNotificationShown = false; + + do + { + var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct); + + if(responseWalletRpc.Error != null) + { + logger.Debug(() => $"`wallet-api` daemon response: {responseWalletRpc.Error.Message} (Code {responseWalletRpc.Error.Code})"); + } + + else + { + var isSynched = (responseExplorerRestClient.Height == responseWalletRpc.Response.Height); + + 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) + { + // coin config + var coin = poolConfig.Template.As(); + + try + { + var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + } + + catch(Exception) + { + throw new PoolStartupException($"Init RPC failed...", poolConfig.Id); + } + + + var request = new ValidateAddressRequest + { + Address = poolConfig.Address + }; + + // address validation + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.ValidateAddress, ct, request); + if(responseWalletRpc.Response?.IsValid == false) + throw new PoolStartupException("Invalid pool address", poolConfig.Id); + + if(responseWalletRpc.Response?.Type.ToLower() != "regular") + throw new PoolStartupException("Pool address must be {'type': 'regular', 'expiration': 'never'}", poolConfig.Id); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + var responseWalletRpc2 = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.ValidateAddress, ct, request); + + // ensure pool owns wallet + if(responseWalletRpc2.Response?.IsMine == false) + throw new PoolStartupException($"Wallet-Daemon does not own pool address '{poolConfig.Address}'", poolConfig.Id); + } + + // update stats + BlockchainStats.RewardType = "POW"; + + // method available only since wallet API v6.1, so upgrade your node in order to enjoy that feature + // https://github.com/BeamMW/beam/wiki/Beam-wallet-protocol-API-v6.1 + var responseNetwork = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetVersion, ct, new {}); + if(responseNetwork.Error == null) + { + BlockchainStats.NetworkType = responseNetwork.Response?.Network; + } + + else + { + BlockchainStats.NetworkType = "N/A [Wallet API >= 6.1]"; + } + + 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) + { + // Prepare data for the stratum API socket + var daemonEndpoint = daemonEndpoints.First(); + var extraDaemonEndpoint = daemonEndpoint.Extra.SafeExtensionDataAs(); + + if(string.IsNullOrEmpty(extraDaemonEndpoint?.ApiKey)) + throw new PoolStartupException("Beam-node daemon `apiKey` not provided", poolConfig.Id); + + var blockFound = blockFoundSubject.Synchronize(); + + var triggers = new List> + { + blockFound.Select(_ => (JobRefreshBy.BlockFound, (string) null)) + }; + + var loginRequest = new GetLoginRequest + { + ApiKey = extraDaemonEndpoint.ApiKey + }; + + // Listen to the stratum API socket + var getWorkSocket = BeamSubscribeStratumApiSocketClient(ct, daemonEndpoint, loginRequest) + .Publish() + .RefCount(); + + triggers.Add(getWorkSocket + .Select(json => (JobRefreshBy.Socket, json)) + .Publish() + .RefCount()); + + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + + Jobs = triggers.Merge() + .Select(x => Observable.FromAsync(() => UpdateJob(ct, x.Via, x.Data))) + .Concat() + .Where(x => x) + .Do(x => + { + if(x) + hasInitialBlockTemplate = true; + }) + .Select(x => GetJobParamsForStratum()) + .Publish() + .RefCount(); + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs b/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs new file mode 100644 index 000000000..520722d40 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs @@ -0,0 +1,348 @@ +using System.Data; +using Autofac; +using AutoMapper; +using Miningcore.Blockchain.Beam.Configuration; +using Miningcore.Blockchain.Beam.DaemonRequests; +using Miningcore.Blockchain.Beam.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.Rest; +using Miningcore.Rpc; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Contract = Miningcore.Contracts.Contract; +using Newtonsoft.Json.Linq; + +namespace Miningcore.Blockchain.Beam; + +[CoinFamily(CoinFamily.Beam)] +public class BeamPayoutHandler : PayoutHandlerBase, + IPayoutHandler +{ + public BeamPayoutHandler( + 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; + } + + private readonly IComponentContext ctx; + private IHttpClientFactory httpClientFactory; + private SimpleRestClient restClient; + private RpcClient rpcClientWallet; + private BeamPoolConfigExtra extraPoolConfig; + private string network; + + protected override string LogCategory => "Beam Payout Handler"; + + private async Task<(bool IsValid, bool IsOffline)> ValidateAddress(string address, CancellationToken ct) + { + if(string.IsNullOrEmpty(address)) + return (false, false); + + var IsOffline = false; + var request = new ValidateAddressRequest + { + Address = address + }; + + // address validation + var responseWalletRpc = await rpcClientWallet.ExecuteAsync(logger, BeamWalletCommands.ValidateAddress, ct, request); + + // Beam wallets come with a lot of flavors + // I tried to enable payments for most of them but there could be some margin for errors + // https://github.com/BeamMW/beam/wiki/Beam-wallet-protocol-API-v7.1#create_address + if (!responseWalletRpc.Response?.IsValid == false) + return (false, IsOffline); + + if (responseWalletRpc.Response?.Type.ToLower() == "max_privacy") + { + logger.Warn(() => $"Worker {address} uses a 'Max Privacy' wallet, intended to be used only one time"); + } + + else if (responseWalletRpc.Response?.Type.ToLower() == "offline") + { + IsOffline = true; + logger.Info(() => $"Worker {address} uses an 'Offline' wallet. Number of offline payments left: {responseWalletRpc.Response?.Payments}"); + return (responseWalletRpc.Response?.Payments > 0, IsOffline); + } + + return (responseWalletRpc.Response?.IsValid == true, IsOffline); + } + + private async Task EnsureBalance(decimal requiredAmount, BeamCoinTemplate coin, CancellationToken ct) + { + var response = await rpcClientWallet.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct, new {}); + + if(response.Error != null) + { + logger.Error(() => $"[{LogCategory}] Daemon command '{BeamWalletCommands.GetBalance}' returned error: {response.Error.Message} code {response.Error.Code}"); + return false; + } + + var balance = Math.Floor(response.Response.Balance / BeamConstants.SmallestUnit); + + if(balance < requiredAmount) + { + logger.Info(() => $"[{LogCategory}] {FormatAmount(requiredAmount)} required for payment, but only have {FormatAmount(balance)} available yet. Will try again."); + return false; + } + + logger.Info(() => $"[{LogCategory}] Current balance is {FormatAmount(balance)}"); + return true; + } + + private async Task PayoutAsync(Balance balance, CancellationToken ct) + { + // send transaction + logger.Info(() => $"[{LogCategory}] Sending {FormatAmount(balance.Amount)} to {balance.Address}"); + + var amount = (ulong) Math.Floor(balance.Amount * BeamConstants.SmallestUnit); + + var (IsValid, IsOffline) = await ValidateAddress(balance.Address, ct); + + var request = new SendTransactionRequest + { + From = poolConfig.Address, + Address = balance.Address, + Value = amount, + Offline = IsOffline + }; + + // send command + var response = await rpcClientWallet.ExecuteAsync(logger, BeamWalletCommands.SendTransaction, ct, request); + + if(response.Error != null) + throw new Exception($"{BeamWalletCommands.SendTransaction} returned error: {response.Error.Message} code {response.Error.Code}"); + + var txHash = response.Response.TxId; + logger.Info(() => $"[{LogCategory}] Payment transaction id: {txHash}"); + + // update db + await PersistPaymentsAsync(new[] { balance }, txHash); + + // done + return txHash; + } + + #region IPayoutHandler + + public virtual async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, CancellationToken ct) + { + Contract.RequiresNonNull(pc); + + poolConfig = pc; + clusterConfig = cc; + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + + logger = LogUtil.GetPoolScopedLogger(typeof(BeamPayoutHandler), pc); + + // configure standard daemon + var jsonSerializerSettings = ctx.Resolve(); + + // configure explorer daemon + var daemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == BeamConstants.ExplorerDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = BeamConstants.ExplorerDaemonRpcStatusLocation; + + return x; + }) + .ToArray(); + + restClient = new SimpleRestClient(httpClientFactory, "http://" + daemonEndpoints.First().Host.ToString() + ":" + daemonEndpoints.First().Port.ToString() + "/"); + + // configure wallet daemon + var walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == BeamConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = BeamConstants.WalletDaemonRpcLocation; + + return x; + }) + .ToArray(); + + rpcClientWallet = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, pc.Id); + + // method available only since wallet API v6.1, so upgrade your node in order to enjoy that feature + // https://github.com/BeamMW/beam/wiki/Beam-wallet-protocol-API-v6.1 + var responseNetwork = await rpcClientWallet.ExecuteAsync(logger, BeamWalletCommands.GetVersion, ct, new {}); + if(responseNetwork.Error != null) + { + network = responseNetwork.Response?.Network; + } + + else + { + network = "N/A [>= wallet API v6.1]"; + } + } + + 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(); + var lastBlock = await restClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + + for(var i = 0; i < pageCount; i++) + { + // get a page full of blocks + var page = blocks + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + // NOTE: beam-node does not support batch-requests??? + for(var j = 0; j < page.Length; j++) + { + var block = page[j]; + + var request = new GetBlockHeaderRequest + { + Height = block.BlockHeight + }; + + var rpcResult = await rpcClientWallet.ExecuteAsync(logger, BeamWalletCommands.GetBlockHeaders, ct, request); + + if(rpcResult.Error != null) + { + logger.Debug(() => $"[{LogCategory}] Daemon reports error '{rpcResult.Error.Message}' (Code {rpcResult.Error.Code}) for block {block.BlockHeight}"); + continue; + } + + // update progress + block.ConfirmationProgress = Math.Min(1.0d, (double) (lastBlock.Height - block.BlockHeight) / BeamConstants.PayoutMinBlockConfirmations); + result.Add(block); + + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + // orphaned? + if(!string.IsNullOrEmpty(rpcResult.Response?.Pow) && rpcResult.Response?.Pow.Contains(block.Hash) == false) + { + block.Hash = null; + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + continue; + } + + // matured and spendable? + if((lastBlock.Height - block.BlockHeight) >= BeamConstants.PayoutMinBlockConfirmations) + { + block.TransactionConfirmationData = rpcResult.Response?.BlockHash; + block.Hash = rpcResult.Response?.BlockHash; + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + block.Reward = GetBaseBlockReward(block.BlockHeight); // base reward + + 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(); + var infoResponse = await restClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); + + if (infoResponse.PeersCount < 3) + { + logger.Warn(() => $"[{LogCategory}] Payout aborted. Not enough peers (4 required)"); + return; + } + + // ensure there's enough balance + if(!await EnsureBalance(balances.Sum(x => x.Amount), coin, ct)) + return; + + var txHashes = new List(); + + foreach(var balance in balances) + { + try + { + var txHash = await PayoutAsync(balance, ct); + txHashes.Add(txHash); + } + + catch(Exception ex) + { + logger.Error(ex); + + NotifyPayoutFailure(poolConfig.Id, new[] { balance }, ex.Message, null); + } + } + + if(txHashes.Any()) + NotifyPayoutSuccess(poolConfig.Id, balances, txHashes.ToArray(), null); + } + + public double AdjustBlockEffort(double effort) + { + return effort; + } + + #endregion // IPayoutHandler + + internal static decimal GetBaseBlockReward(ulong height) + { + // BEAM block reward distribution - https://github.com/BeamMW/beam/wiki/BEAM-Mining + if (height > BeamConstants.EmisssionThirdEpochHeight) + { + double heightEraLength = (height - BeamConstants.EmisssionThirdEpochHeight) / BeamConstants.EraLength; + double era = Math.Truncate(heightEraLength); + decimal quotient = Convert.ToDecimal(Math.Pow(BeamConstants.DisinflationRateQuotient, era)); + decimal divisor = Convert.ToDecimal(Math.Pow(BeamConstants.DisinflationRateDivisor, era)); + return ((BeamConstants.EmisssionSecondEpochBlockReward * quotient) / divisor); + } + + else if (height > BeamConstants.EmisssionFirstEpochHeight) + { + return BeamConstants.EmisssionFirstEpochBlockReward; + } + + else + { + return BeamConstants.BaseRewardInitial; + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamPool.cs b/src/Miningcore/Blockchain/Beam/BeamPool.cs new file mode 100644 index 000000000..2ba6d2759 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamPool.cs @@ -0,0 +1,492 @@ +using System.Globalization; +using System.Numerics; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using Autofac; +using AutoMapper; +using Microsoft.IO; +using Miningcore.Blockchain.Beam.StratumRequests; +using Miningcore.Blockchain.Beam.StratumResponses; +using Miningcore.Blockchain.Beam.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 Miningcore.Util; +using Newtonsoft.Json; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Beam; + +[CoinFamily(CoinFamily.Beam)] +public class BeamPool : PoolBase +{ + public BeamPool(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) + { + } + + protected BeamJobManager manager; + private BeamCoinTemplate coin; + + private async Task OnLoginAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + // Beam stratum API: https://github.com/BeamMW/beam/wiki/Beam-mining-protocol-API-(Stratum) + var request = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(tsRequest.Value)); + + if(request.Login == null) + throw new StratumException(StratumError.MinusOne, "Login failed: missing 'api_key'"); + + var context = connection.ContextAs(); + var workerValue = request?.Login; + var password = !string.IsNullOrEmpty(request?.Password) ? request.Password : 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 workerName is an address + context.IsAuthorized = await manager.ValidateAddressAsync(minerName, ct); + context.Miner = minerName; + context.Worker = workerName; + + 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 data = new object[] + { + connection.ConnectionId, + } + .Concat(manager.GetSubscriberData(connection)) + .ToArray(); + + // setup worker context + context.IsSubscribed = true; + context.UserAgent = request?.UserAgent; + + // response + var loginResponse = new BeamLoginResponse { + Code = BeamConstants.BeamRpcLoginSuccess, + Description = "Login successful", + Nonceprefix = connection.ConnectionId, + Forkheight = manager?.Forkheight, + Forkheight2 = manager?.Forkheight2 + }; + + // respond + await connection.NotifyAsync(loginResponse); + + // log association + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); + + var currentJobParams = manager.GetJobParamsForStratum(); + logger.Info(() => $"Broadcasting job {currentJobParams[0]}"); + + // response + var jobResponse = new BeamJobResponse { + Id = (string) currentJobParams[0], + Height = (ulong) currentJobParams[1], + Difficulty = BeamUtils.PackedDifficulty(connection.Context.Difficulty), + Input = (string) currentJobParams[4] + }; + + // respond + await connection.NotifyAsync(jobResponse); + } + + else + { + // response + var loginFailureResponse = new BeamLoginResponse { + Code = BeamConstants.BeamRpcLoginFailure, + Description = "Login failed" + }; + + // respond + await connection.NotifyAsync(loginFailureResponse); + + 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); + } + } + } + + 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) + var request = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(tsRequest.Value)); + var context = connection.ContextAs(); + + try + { + if(request?.Id == null) + throw new StratumException(StratumError.MinusOne, "missing 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) + { + // response + var submitIsAuthorizedResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcUnauthorizedWorker, + Description = "Unauthorized worker, please login first", + }; + + // respond + await connection.NotifyAsync(submitIsAuthorizedResponse); + throw new StratumException(StratumError.UnauthorizedWorker, "Unauthorized worker, please login first"); + } + + else if(!context.IsSubscribed) + { + // response + var submitIsSubscribedResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcNotSubscribed, + Description = "Worker not subscribed" + }; + + // respond + await connection.NotifyAsync(submitIsSubscribedResponse); + throw new StratumException(StratumError.NotSubscribed, "Worker not subscribed"); + } + + else + { + // submit + var (share, stratumError) = manager.SubmitShare(connection, request?.Id, request?.Nonce, request?.Output, ct); + + if (stratumError == BeamConstants.BeamRpcInvalidShare) + { + // response + var submitInvalidShareResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcInvalidShare, + Description = "Invalid Share" + }; + + // respond + await connection.NotifyAsync(submitInvalidShareResponse); + throw new StratumException(StratumError.Other, "Invalid Share"); + } + + else if (stratumError == BeamConstants.BeamRpcLowDifficultyShare) + { + // response + var submitLowDifficultyShareResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcLowDifficultyShare, + Description = $"low difficulty share ({share.Difficulty})" + }; + + // respond + await connection.NotifyAsync(submitLowDifficultyShareResponse); + throw new StratumException(StratumError.Other, $"low difficulty share ({share.Difficulty})"); + } + + else if (stratumError == BeamConstants.BeamRpcShareBadNonce) + { + // response + var submitShareBadNonceResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcShareBadNonce, + Description = $"incorrect size of nonce ({request?.Nonce.Length}), expected: {BeamConstants.NonceSize}" + }; + + // respond + await connection.NotifyAsync(submitShareBadNonceResponse); + throw new StratumException(StratumError.Other, $"incorrect size of nonce ({request?.Nonce.Length}), expected: {BeamConstants.NonceSize}"); + } + + else if (stratumError == BeamConstants.BeamRpcShareBadSolution) + { + // response + var submitShareBadSolutionResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcShareBadSolution, + Description = $"incorrect size of solution ({request?.Output.Length}), expected: {BeamConstants.SolutionSize}" + }; + + // respond + await connection.NotifyAsync(submitShareBadSolutionResponse); + throw new StratumException(StratumError.Other, $"incorrect size of solution ({request?.Output.Length}), expected: {BeamConstants.SolutionSize}"); + } + + else if (stratumError == BeamConstants.BeamRpcDuplicateShare) + { + // response + var submitDuplicateShareResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcDuplicateShare, + Description = "duplicate share" + }; + + // respond + await connection.NotifyAsync(submitDuplicateShareResponse); + throw new StratumException(StratumError.Other, "duplicate share"); + } + + else if (stratumError == BeamConstants.BeamRpcJobNotFound) + { + // response + var submitJobNotFoundResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcJobNotFound, + Description = "job not found" + }; + + // respond + await connection.NotifyAsync(submitJobNotFoundResponse); + throw new StratumException(StratumError.Other, "job not found"); + } + + else + { + // response + var shareAcceptedResponse = new BeamSubmitResponse { + Id = request?.Id, + Code = BeamConstants.BeamRpcShareAccepted, + Description = "accepted" + }; + + await connection.NotifyAsync(shareAcceptedResponse); + + // 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); + + throw; + } + } + + protected async Task OnNewJobAsync(object[] jobParams) + { + var currentJobParams = jobParams; + + logger.Info(() => $"Broadcasting job {currentJobParams[0]}"); + + await Guard(() => ForEachMinerAsync(async (connection, ct) => + { + var context = connection.ContextAs(); + + // response + var jobResponse = new BeamJobResponse { + Id = (string) currentJobParams[0], + Height = (ulong) currentJobParams[1], + Difficulty = BeamUtils.PackedDifficulty(context.Difficulty), + Input = (string) currentJobParams[4] + }; + + // respond + await connection.NotifyAsync(jobResponse); + })); + } + + #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( + new TypedParameter(typeof(IExtraNonceProvider), new BeamExtraNonceProvider(poolConfig.Id, 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 async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + try + { + switch(request.Method) + { + case BeamStratumMethods.Login: + await OnLoginAsync(connection, tsRequest, ct); + break; + + case BeamStratumMethods.Submit: + 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); + } + } + + public override double HashrateFromShares(double shares, double interval) + { + var result = shares / interval; + return result; + } + + public override double ShareMultiplier => 1; + + protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) + { + await base.OnVarDiffUpdateAsync(connection, newDiff, ct); + + if(connection.Context.ApplyPendingDifficulty()) + { + var currentJobParams = manager.GetJobParamsForStratum(); + + // response + var jobResponse = new BeamJobResponse { + Id = (string) currentJobParams[0], + Height = (ulong) currentJobParams[1], + Difficulty = BeamUtils.PackedDifficulty(connection.Context.Difficulty), + Input = (string) currentJobParams[4] + }; + + // respond + await connection.NotifyAsync(jobResponse); + } + } + + protected override WorkerContextBase CreateWorkerContext() + { + return new BeamWorkerContext(); + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamStratumMethods.cs b/src/Miningcore/Blockchain/Beam/BeamStratumMethods.cs new file mode 100644 index 000000000..a75c86b48 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamStratumMethods.cs @@ -0,0 +1,20 @@ + +namespace Miningcore.Blockchain.Beam; + +public class BeamStratumMethods +{ + /// + /// Used to subscribe to work + /// + public const string Login = "login"; + + /// + /// New job notification + /// + public const string JobNotify = "job"; + + /// + /// Submit share request + /// + public const string Submit = "solution"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamUtils.cs b/src/Miningcore/Blockchain/Beam/BeamUtils.cs new file mode 100644 index 000000000..70f77dd51 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamUtils.cs @@ -0,0 +1,24 @@ +using System; +using System.Numerics; + +namespace Miningcore.Blockchain.Beam; + +public static class BeamUtils +{ + public static double UnpackedDifficulty(long packedDifficulty) + { + uint leadingBit = 1 << 24; + long order = packedDifficulty >> 24; + double result = (leadingBit | (packedDifficulty & leadingBit - 1)) * Math.Pow(2, order - 24); + return (double) Math.Abs(result); + } + + public static long PackedDifficulty(double unpackedDifficulty) + { + long bits = 32 - BitOperations.LeadingZeroCount(Convert.ToUInt32(Math.Round(unpackedDifficulty, MidpointRounding.ToEven))); + long correctedOrder = bits - 24 - 1; + long mantissa = (long) (unpackedDifficulty * Math.Pow(2, -correctedOrder) - Math.Pow(2, 24)); + long order = 24 + correctedOrder; + return (long) (mantissa | (order << 24)); + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs b/src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs new file mode 100644 index 000000000..27216fa63 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/BeamWorkerContext.cs @@ -0,0 +1,21 @@ +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Beam; + +public class BeamWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } +} diff --git a/src/Miningcore/Blockchain/Beam/Configuration/BeamDaemonEndpointConfigExtra.cs b/src/Miningcore/Blockchain/Beam/Configuration/BeamDaemonEndpointConfigExtra.cs new file mode 100644 index 000000000..0cceb22a6 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/Configuration/BeamDaemonEndpointConfigExtra.cs @@ -0,0 +1,9 @@ +namespace Miningcore.Blockchain.Beam.Configuration; + +public class BeamDaemonEndpointConfigExtra +{ + /// + /// Miner registration key + /// + public string ApiKey { get; set; } = null; +} diff --git a/src/Miningcore/Blockchain/Beam/Configuration/BeamPoolConfigExtra.cs b/src/Miningcore/Blockchain/Beam/Configuration/BeamPoolConfigExtra.cs new file mode 100644 index 000000000..91c71e094 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/Configuration/BeamPoolConfigExtra.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Miningcore.Blockchain.Beam.Configuration; + +public class BeamPoolConfigExtra +{ + /// + /// Maximum number of tracked jobs. + /// Default: 4 - you should increase this value if beam-node is higher than 300ms + /// + public int? MaxActiveJobs { get; set; } +} diff --git a/src/Miningcore/Blockchain/Beam/DaemonRequests/GetBlockHeaderRequest.cs b/src/Miningcore/Blockchain/Beam/DaemonRequests/GetBlockHeaderRequest.cs new file mode 100644 index 000000000..fe1adc13f --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonRequests/GetBlockHeaderRequest.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonRequests; + +public class GetBlockHeaderRequest +{ + [JsonProperty("height")] + public ulong Height { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonRequests/GetLoginRequest.cs b/src/Miningcore/Blockchain/Beam/DaemonRequests/GetLoginRequest.cs new file mode 100644 index 000000000..4d55fdcb0 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonRequests/GetLoginRequest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonRequests; + +public class GetLoginRequest +{ + [JsonProperty("id")] + public string Id { get; set; } = "login"; + + [JsonProperty("method")] + public string Method { get; set; } = "login"; + + [JsonProperty("api_key")] + public string ApiKey { get; set; } + + [JsonProperty("jsonrpc")] + public string JsonRpc { get; set; } = "2.0"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonRequests/SendTransactionRequest.cs b/src/Miningcore/Blockchain/Beam/DaemonRequests/SendTransactionRequest.cs new file mode 100644 index 000000000..7a69a9031 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonRequests/SendTransactionRequest.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonRequests; + +public class SendTransactionRequest +{ + public string From { get; set; } + public string Address { get; set; } + public ulong Value { get; set; } + + // Always in BEAM groth, optional. Omit for default fee. + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public ulong? Fee { get; set; } + + // asset id to send, optional. Present starting from v5.0 and can be used only after Fork 2. + // Omit or set to 0 for BEAM transaction. + // If asset_id is non-zero assets must be enabled (--enable_assets) or method would fail. + [JsonProperty("asset_id")] + public ulong AssetId { get; set; } = 0; + + // Since v6.0 offline addresses by default start the regular online transaction. + // Specify "offline":true" to start an offline transaction. + // Applied only for offline addresses and ignored for all other address types. + public bool Offline { get; set; } = false; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonRequests/ValidateAddressRequest.cs b/src/Miningcore/Blockchain/Beam/DaemonRequests/ValidateAddressRequest.cs new file mode 100644 index 000000000..5d443892d --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonRequests/ValidateAddressRequest.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonRequests; + +public class ValidateAddressRequest +{ + [JsonProperty("address")] + public string Address { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBalanceResponse.cs b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBalanceResponse.cs new file mode 100644 index 000000000..069338d74 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBalanceResponse.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonResponses; + +public class GetBalanceResponse +{ + [JsonProperty("current_height")] + public ulong Height { get; set; } + + [JsonProperty("available")] + public ulong Balance { get; set; } + + [JsonProperty("is_in_sync")] + public bool IsInSync { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockHeaderResponse.cs b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockHeaderResponse.cs new file mode 100644 index 000000000..a5333e913 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockHeaderResponse.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonResponses; + +public class GetBlockHeaderResponse +{ + [JsonProperty("block_hash")] + public string BlockHash { get; set; } + + public string Chainwork { get; set; } + public string Definition { get; set; } + public double Difficulty { get; set; } + public ulong Height { get; set; } + public string Kernels { get; set; } + + [JsonProperty("packed_difficulty")] + public long PackedDifficulty { get; set; } + + public string Pow { get; set; } + + [JsonProperty("previous_block")] + public string PreviousBlock { get; set; } + + [JsonProperty("rules_hash")] + public string RulesHash { get; set; } + + public ulong Timestamp { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockTemplateResponse.cs b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockTemplateResponse.cs new file mode 100644 index 000000000..fcbe73311 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetBlockTemplateResponse.cs @@ -0,0 +1,27 @@ +using System.Numerics; +using Miningcore.Serialization; +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonResponses; + +public class BeamBlockTemplate +{ + [JsonProperty("id")] + public string JobId { get; set; } + + [JsonProperty("height")] + public ulong Height { get; set; } + + public double Difficulty { get; set; } + + [JsonProperty("difficulty")] + public long PackedDifficulty { get; set; } + + public string Input { get; set; } + + // Beamhash version + // 0: Beam Hash I + // 1: Beam Hash II + // 2: Beam Hash III + public int PowType { get; set; } = 0; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonResponses/GetStatusResponse.cs b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetStatusResponse.cs new file mode 100644 index 000000000..80e7c7039 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetStatusResponse.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Beam.DaemonResponses; + +public record GetStatusResponse +{ + public string Chainwork { get; set; } + public string Hash { get; set; } + public ulong Height { get; set; } + + [JsonPropertyName("peers_count")] + public int PeersCount { get; set; } + + public ulong Timestamp { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonResponses/GetVersionResponse.cs b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetVersionResponse.cs new file mode 100644 index 000000000..6a3b922a7 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonResponses/GetVersionResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonResponses; + +public class GetVersionResponse +{ + [JsonProperty("beam_network_name")] + public string Network { get; set; } + + [JsonProperty("api_version")] + public decimal ApiVersion { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonResponses/SendTransactionResponse.cs b/src/Miningcore/Blockchain/Beam/DaemonResponses/SendTransactionResponse.cs new file mode 100644 index 000000000..62368ddb8 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonResponses/SendTransactionResponse.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonResponses; + +public class SendTransactionResponse +{ + [JsonProperty("txId")] + public string TxId { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/DaemonResponses/ValidateAddressResponse.cs b/src/Miningcore/Blockchain/Beam/DaemonResponses/ValidateAddressResponse.cs new file mode 100644 index 000000000..4ae0e405d --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/DaemonResponses/ValidateAddressResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.DaemonResponses; + +public class ValidateAddressResponse +{ + [JsonProperty("is_valid")] + public bool IsValid { get; set; } + [JsonProperty("is_mine")] + public bool IsMine { get; set; } + public string Type { get; set; } = null; + public int Payments { get; set; } = 0; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/StratumRequests/BeamLoginRequest.cs b/src/Miningcore/Blockchain/Beam/StratumRequests/BeamLoginRequest.cs new file mode 100644 index 000000000..4c9cef34c --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/StratumRequests/BeamLoginRequest.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.StratumRequests; + +public class BeamLoginRequest +{ + [JsonProperty("api_key")] + public string Login { get; set; } + + [JsonProperty("pass")] + public string Password { get; set; } = null; + + [JsonProperty("agent")] + public string UserAgent { get; set; } = null; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/StratumRequests/BeamSubmitRequest.cs b/src/Miningcore/Blockchain/Beam/StratumRequests/BeamSubmitRequest.cs new file mode 100644 index 000000000..bb6edf589 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/StratumRequests/BeamSubmitRequest.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.StratumRequests; + +public class BeamSubmitRequest +{ + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("method")] + public string Method { get; set; } = "solution"; + + [JsonProperty("nonce")] + public string Nonce { get; set; } + + [JsonProperty("output")] + public string Output { get; set; } + + [JsonProperty("jsonrpc")] + public string Jsonrpc { get; set; } = "2.0"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs new file mode 100644 index 000000000..9c8647c08 --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.StratumResponses; + +public class BeamJobResponse : BeamResponseBase +{ + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("height")] + public ulong Height { get; set; } + + [JsonProperty("difficulty")] + public long Difficulty { get; set; } + + [JsonProperty("input")] + public string Input { get; set; } + + [JsonProperty("method")] + public string Method { get; set; } = "job"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/StratumResponses/BeamLoginResponse.cs b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamLoginResponse.cs new file mode 100644 index 000000000..0bf7b747c --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamLoginResponse.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.StratumResponses; + +public class BeamLoginResponse : BeamResponseBase +{ + [JsonProperty("id")] + public string Id { get; set; } = "login"; + + [JsonProperty("nonceprefix", NullValueHandling = NullValueHandling.Ignore)] + public string Nonceprefix { get; set; } = null; + + [JsonProperty("forkheight", NullValueHandling = NullValueHandling.Ignore)] + public ulong? Forkheight { get; set; } + + [JsonProperty("forkheight2", NullValueHandling = NullValueHandling.Ignore)] + public ulong? Forkheight2 { get; set; } + + [JsonProperty("method")] + public string Method { get; set; } = "result"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/StratumResponses/BeamResponseBase.cs b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamResponseBase.cs new file mode 100644 index 000000000..96100885c --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamResponseBase.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.StratumResponses; + +public class BeamResponseBase +{ + [JsonProperty("code", NullValueHandling = NullValueHandling.Ignore)] + public short? Code { get; set; } + + [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] + public string Description { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/StratumResponses/BeamSubmitResponse.cs b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamSubmitResponse.cs new file mode 100644 index 000000000..60349a8dc --- /dev/null +++ b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamSubmitResponse.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Beam.StratumResponses; + +public class BeamSubmitResponse : BeamResponseBase +{ + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("method")] + public string Method { get; set; } = "result"; + + [JsonProperty("blockhash", NullValueHandling = NullValueHandling.Ignore)] + public string BlockHash { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 0557ac076..38ea3701e 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -593,7 +593,7 @@ public void Init(BlockTemplate blockTemplate, string jobId, { masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if(coin.HasSmartNodes) + if((coin.Symbol == "RTM") || (coin.Symbol == "THOON") || (coin.Symbol == "YERB") || (coin.Symbol == "BTRM")) { if(masterNodeParameters.Extra?.ContainsKey("smartnode") == true) { diff --git a/src/Miningcore/Blockchain/Constants.cs b/src/Miningcore/Blockchain/Constants.cs index cfb0f2d9e..de65738ed 100644 --- a/src/Miningcore/Blockchain/Constants.cs +++ b/src/Miningcore/Blockchain/Constants.cs @@ -9,5 +9,6 @@ public static class JobRefreshBy public const string BlockTemplateStream = "BTS"; public const string BlockTemplateStreamRefresh = "BTS-R"; public const string WebSocket = "WS"; + public const string Socket = "S"; public const string BlockFound = "BLOCK"; } diff --git a/src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs b/src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs new file mode 100644 index 000000000..5a5f39be0 --- /dev/null +++ b/src/Miningcore/Blockchain/Equihash/Custom/Veruscoin/VeruscoinJob.cs @@ -0,0 +1,650 @@ +using System.Globalization; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Equihash.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Contracts; +using Miningcore.Crypto.Hashing.Equihash; +using Miningcore.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using NBitcoin; +using NBitcoin.DataEncoders; +using NBitcoin.Zcash; + +namespace Miningcore.Blockchain.Equihash.Custom.Veruscoin; + +public class VeruscoinJob : EquihashJob +{ + // PBaaS + public bool isPBaaSActive; + + protected uint coinbaseIndex = 4294967295u; + protected uint coinbaseSequence = 4294967295u; + // protected string poolHex = "56525343"; + private static uint txInputCount = 1u; + private static uint txLockTime; + private static uint txExpiryHeight = 0u; + private static long txBalance = 0; + private static uint txVShieldedSpend = 0u; + private static uint txVShieldedOutput = 0u; + private static uint txJoinSplits = 0u; + + protected override Transaction CreateOutputTransaction() + { + var txNetwork = Network.GetNetwork(networkParams.CoinbaseTxNetwork); + var tx = Transaction.Create(txNetwork); + + // set versions + tx.Version = txVersion; + + /* if(isOverwinterActive) + { + overwinterField.SetValue(tx, true); + versionGroupField.SetValue(tx, txVersionGroupId); + } */ + + // calculate outputs + if(networkParams.PayFundingStream) + { + rewardToPool = new Money(Math.Round(blockReward * (1m - (networkParams.PercentFoundersReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); + tx.Outputs.Add(rewardToPool, poolAddressDestination); + + foreach(FundingStream fundingstream in BlockTemplate.Subsidy.FundingStreams) + { + var amount = new Money(Math.Round(fundingstream.ValueZat / 1m), MoneyUnit.Satoshi); + var destination = FoundersAddressToScriptDestination(fundingstream.Address); + tx.Outputs.Add(amount, destination); + } + } + else if(networkParams.vOuts) + { + rewardToPool = new Money(Math.Round(blockReward * (1m - (networkParams.vPercentFoundersReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); + tx.Outputs.Add(rewardToPool, poolAddressDestination); + var destination = FoundersAddressToScriptDestination(networkParams.vTreasuryRewardAddress); + var amount = new Money(Math.Round(blockReward * (networkParams.vPercentTreasuryReward / 100m)), MoneyUnit.Satoshi); + tx.Outputs.Add(amount, destination); + destination = FoundersAddressToScriptDestination(networkParams.vSecureNodesRewardAddress); + amount = new Money(Math.Round(blockReward * (networkParams.percentSecureNodesReward / 100m)), MoneyUnit.Satoshi); + tx.Outputs.Add(amount, destination); + destination = FoundersAddressToScriptDestination(networkParams.vSuperNodesRewardAddress); + amount = new Money(Math.Round(blockReward * (networkParams.percentSuperNodesReward / 100m)), MoneyUnit.Satoshi); + tx.Outputs.Add(amount, destination); + } + else if(networkParams.PayFoundersReward && + (networkParams.LastFoundersRewardBlockHeight >= BlockTemplate.Height || + networkParams.TreasuryRewardStartBlockHeight > 0)) + { + // founders or treasury reward? + if(networkParams.TreasuryRewardStartBlockHeight > 0 && + BlockTemplate.Height >= networkParams.TreasuryRewardStartBlockHeight) + { + // pool reward (t-addr) + rewardToPool = new Money(Math.Round(blockReward * (1m - (networkParams.PercentTreasuryReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); + tx.Outputs.Add(rewardToPool, poolAddressDestination); + + // treasury reward (t-addr) + var destination = FoundersAddressToScriptDestination(GetVeruscoinTreasuryRewardAddress()); + var amount = new Money(Math.Round(blockReward * (networkParams.PercentTreasuryReward / 100m)), MoneyUnit.Satoshi); + tx.Outputs.Add(amount, destination); + } + + else + { + // pool reward (t-addr) + rewardToPool = new Money(Math.Round(blockReward * (1m - (networkParams.PercentFoundersReward) / 100m)) + rewardFees, MoneyUnit.Satoshi); + tx.Outputs.Add(rewardToPool, poolAddressDestination); + + // founders reward (t-addr) + var destination = FoundersAddressToScriptDestination(GetFoundersRewardAddress()); + var amount = new Money(Math.Round(blockReward * (networkParams.PercentFoundersReward / 100m)), MoneyUnit.Satoshi); + tx.Outputs.Add(amount, destination); + } + } + + else + { + // no founders reward + // pool reward (t-addr) + rewardToPool = new Money(blockReward + rewardFees, MoneyUnit.Satoshi); + tx.Outputs.Add(rewardToPool, poolAddressDestination); + } + + tx.Inputs.Add(TxIn.CreateCoinbase((int) BlockTemplate.Height)); + + return tx; + } + + private string GetVeruscoinTreasuryRewardAddress() + { + var index = (int) Math.Floor((BlockTemplate.Height - networkParams.TreasuryRewardStartBlockHeight) / + networkParams.TreasuryRewardAddressChangeInterval % networkParams.TreasuryRewardAddresses.Length); + + var address = networkParams.TreasuryRewardAddresses[index]; + return address; + } + + protected override void BuildCoinbase() + { + // output transaction + txOut = CreateOutputTransaction(); + + // when PBaaS activates we must use the coinbasetxn from daemon to get proper fee pool calculations in coinbase + var solutionVersion = BlockTemplate.Solution.Substring(0, 8); + var reversedSolutionVersion = uint.Parse(solutionVersion.HexToReverseByteArray().ToHexString(), NumberStyles.HexNumber); + isPBaaSActive = (reversedSolutionVersion > 6); + + if(!isPBaaSActive) + { + var script = TxIn.CreateCoinbase((int) BlockTemplate.Height).ScriptSig; + + /* var blockHeight = (int) BlockTemplate.Height; + var blockHeightSerial = blockHeight.ToString(); + if (blockHeightSerial.Length % 2 != 0) + blockHeightSerial = "0" + blockHeightSerial; + + int shiftedHeight = blockHeight << 1; + int height = (int) Math.Ceiling((double) shiftedHeight.ToString().Length / 8); + int lengthDiff = blockHeightSerial.Length / 2 - height; + for (int i = 0; i < lengthDiff; i++) { + blockHeightSerial += "00"; + } + + var length = "0" + height.ToString(); + + var lengthBytes = (Span) length.HexToByteArray(); + var blockHeightSerialBytes = (Span) blockHeightSerial.HexToReverseByteArray(); + var opBytes = (Span) new byte[] { 0x00 }; + var poolHexBytes = (Span) poolHex.HexToByteArray(); + + // concat length, blockHeightSerial, OP_0 and poolHex + Span serializedBlockHeightBytes = stackalloc byte[lengthBytes.Length + blockHeightSerialBytes.Length + opBytes.Length + poolHexBytes.Length]; + lengthBytes.CopyTo(serializedBlockHeightBytes); + var offset = lengthBytes.Length; + blockHeightSerialBytes.CopyTo(serializedBlockHeightBytes[offset..]); + offset += blockHeightSerialBytes.Length; + opBytes.CopyTo(serializedBlockHeightBytes[offset..]); + offset += poolHexBytes.Length; + poolHexBytes.CopyTo(serializedBlockHeightBytes[offset..]); */ + + using(var stream = new MemoryStream()) + { + var bs = new ZcashStream(stream, true); + + bs.Version = txVersion; + bs.Overwintered = isOverwinterActive; + + /* if(isOverwinterActive) + { + uint mask = (isOverwinterActive ? 1u : 0u ); + uint shiftedMask = mask << 31; + uint versionWithOverwinter = txVersion | shiftedMask; + + // version + bs.ReadWrite(ref versionWithOverwinter); + } + else + { + // version + bs.ReadWrite(ref txVersion); + } + + if(isOverwinterActive || isSaplingActive) + { + bs.ReadWrite(ref txVersionGroupId); + } */ + + // serialize (simulated) input transaction + bs.ReadWriteAsVarInt(ref txInputCount); + bs.ReadWrite(ref sha256Empty); + bs.ReadWrite(ref coinbaseIndex); + // bs.ReadWrite(ref serializedBlockHeightBytes); + bs.ReadWrite(ref script); + bs.ReadWrite(ref coinbaseSequence); + + // serialize output transaction + var txOutBytes = SerializeOutputTransaction(txOut); + bs.ReadWrite(ref txOutBytes); + + // misc + bs.ReadWrite(ref txLockTime); + + if(isOverwinterActive || isSaplingActive) + { + bs.ReadWrite(ref txExpiryHeight); + } + + if(isSaplingActive) + { + bs.ReadWrite(ref txBalance); + bs.ReadWriteAsVarInt(ref txVShieldedSpend); + bs.ReadWriteAsVarInt(ref txVShieldedOutput); + } + + if(isOverwinterActive || isSaplingActive) + { + bs.ReadWriteAsVarInt(ref txJoinSplits); + } + + // done + coinbaseInitial = stream.ToArray(); + coinbaseInitialHash = new byte[32]; + sha256D.Digest(coinbaseInitial, coinbaseInitialHash); + } + } + else + { + coinbaseInitial = BlockTemplate.CoinbaseTx.Data.HexToByteArray(); + coinbaseInitialHash = BlockTemplate.CoinbaseTx.Hash.HexToReverseByteArray(); + } + } + + private byte[] SerializeOutputTransaction(Transaction tx) + { + var withDefaultWitnessCommitment = !string.IsNullOrEmpty(BlockTemplate.DefaultWitnessCommitment); + + var outputCount = (uint) tx.Outputs.Count; + if(withDefaultWitnessCommitment) + outputCount++; + + using(var stream = new MemoryStream()) + { + var bs = new BitcoinStream(stream, true); + + // write output count + bs.ReadWriteAsVarInt(ref outputCount); + + long amount; + byte[] raw; + uint rawLength; + + // serialize outputs + foreach(var output in tx.Outputs) + { + amount = output.Value.Satoshi; + var outScript = output.ScriptPubKey; + raw = outScript.ToBytes(true); + rawLength = (uint) raw.Length; + + bs.ReadWrite(ref amount); + bs.ReadWriteAsVarInt(ref rawLength); + bs.ReadWrite(ref raw); + } + + // serialize witness (segwit) + if(withDefaultWitnessCommitment) + { + amount = 0; + raw = BlockTemplate.DefaultWitnessCommitment.HexToByteArray(); + rawLength = (uint) raw.Length; + + bs.ReadWrite(ref amount); + bs.ReadWriteAsVarInt(ref rawLength); + bs.ReadWrite(ref raw); + } + + return stream.ToArray(); + } + } + + private byte[] BuildVeruscoinRawTransactionBuffer() + { + using(var stream = new MemoryStream()) + { + foreach(var tx in BlockTemplate.Transactions) + { + var txRaw = tx.Data.HexToByteArray(); + stream.Write(txRaw); + } + + return stream.ToArray(); + } + } + + private byte[] SerializeVeruscoinBlock(Span header, Span coinbase, Span solution) + { + var transactionCount = (uint) BlockTemplate.Transactions.Length + 1; // +1 for prepended coinbase tx + var rawTransactionBuffer = BuildVeruscoinRawTransactionBuffer(); + + using(var stream = new MemoryStream()) + { + var bs = new BitcoinStream(stream, true); + + bs.ReadWrite(ref header); + bs.ReadWrite(ref solution); + + /* var txCount = transactionCount.ToString(); + if (Math.Abs(txCount.Length % 2) == 1) + txCount = "0" + txCount; + + if (transactionCount <= 0x7f) + { + var simpleVarIntBytes = (Span) txCount.HexToByteArray(); + + bs.ReadWrite(ref simpleVarIntBytes); + } + else if (transactionCount <= 0x7fff) + { + if (txCount.Length == 2) + txCount = "00" + txCount; + + var complexHeader = (Span) new byte[] { 0xFD }; + var complexVarIntBytes = (Span) txCount.HexToReverseByteArray(); + + // concat header and varInt + Span complexHeaderVarIntBytes = stackalloc byte[complexHeader.Length + complexVarIntBytes.Length]; + complexHeader.CopyTo(complexHeaderVarIntBytes); + complexVarIntBytes.CopyTo(complexHeaderVarIntBytes[complexHeader.Length..]); + + bs.ReadWrite(ref complexHeaderVarIntBytes); + } */ + + bs.ReadWriteAsVarInt(ref transactionCount); + bs.ReadWrite(ref coinbase); + bs.ReadWrite(ref rawTransactionBuffer); + + return stream.ToArray(); + } + } + + private (Share Share, string BlockHex) ProcessVersucoinShareInternal(StratumConnection worker, string nonce, + uint nTime, string solution) + { + var context = worker.ContextAs(); + var solutionBytes = (Span) solution.HexToByteArray(); + + // serialize block-header + var headerBytes = SerializeHeader(nTime, nonce); + + // concat header and solution + Span headerSolutionBytes = stackalloc byte[headerBytes.Length + solutionBytes.Length]; + headerBytes.CopyTo(headerSolutionBytes); + + solutionBytes.CopyTo(headerSolutionBytes[headerBytes.Length..]); + + // hash block-header + Span headerHash = stackalloc byte[32]; + + Verushash headerHasherVerus = new Verushash(); + + if (BlockTemplate.Version > 4 && !string.IsNullOrEmpty(BlockTemplate.Solution)) + { + // make sure verus solution version matches expected version + if (solution.Substring(VeruscoinConstants.SolutionSlice, 2) != BlockTemplate.Solution.Substring(0, 2)) + throw new StratumException(StratumError.Other, $"invalid solution - expected solution header: {BlockTemplate.Solution.Substring(0, 2)}"); + + if (solution.Substring(VeruscoinConstants.SolutionSlice, 2) == "03") + headerHasherVerus.Digest(headerSolutionBytes, headerHash, VeruscoinConstants.HashVersion2b1); + else + headerHasherVerus.Digest(headerSolutionBytes, headerHash, VeruscoinConstants.HashVersion2b2); + } + else if (BlockTemplate.Version > 4) + headerHasherVerus.Digest(headerSolutionBytes, headerHash, VeruscoinConstants.HashVersion2b); + else + headerHasherVerus.Digest(headerSolutionBytes, headerHash); + + var headerValue = new uint256(headerHash); + + // calc share-diff + var shareDiff = (double) new BigRational(networkParams.Diff1BValue, headerHash.ToBigInteger()); + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = headerValue <= 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, + }; + + if(isBlockCandidate) + { + var headerHashReversed = headerHash.ToNewReverseArray(); + + result.IsBlockCandidate = true; + result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC); + result.BlockHash = headerHashReversed.ToHexString(); + var blockBytes = SerializeVeruscoinBlock(headerBytes, coinbaseInitial, solutionBytes); + var blockHex = blockBytes.ToHexString(); + + return (result, blockHex); + } + + return (result, null); + } + + private bool RegisterVersucoinSubmit(string nonce, string solution) + { + var key = nonce + solution; + + return submissions.TryAdd(key, true); + } + + #region API-Surface + + public override void Init(EquihashBlockTemplate blockTemplate, string jobId, + PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, + IDestination poolAddressDestination, Network network, + EquihashSolver solver) + { + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(clusterConfig); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(poolAddressDestination); + Contract.RequiresNonNull(solver); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + + this.clock = clock; + this.poolAddressDestination = poolAddressDestination; + coin = poolConfig.Template.As(); + networkParams = coin.GetNetwork(network.ChainName); + this.network = network; + BlockTemplate = blockTemplate; + JobId = jobId; + Difficulty = (double) new BigRational(networkParams.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); + + // ZCash Sapling & Overwinter support + isSaplingActive = networkParams.SaplingActivationHeight.HasValue && + networkParams.SaplingTxVersion.HasValue && + networkParams.SaplingTxVersionGroupId.HasValue && + networkParams.SaplingActivationHeight.Value > 0 && + blockTemplate.Height >= networkParams.SaplingActivationHeight.Value; + + isOverwinterActive = isSaplingActive || + networkParams.OverwinterTxVersion.HasValue && + networkParams.OverwinterTxVersionGroupId.HasValue && + networkParams.OverwinterActivationHeight.HasValue && + networkParams.OverwinterActivationHeight.Value > 0 && + blockTemplate.Height >= networkParams.OverwinterActivationHeight.Value; + + if(isSaplingActive) + { + txVersion = networkParams.SaplingTxVersion.Value; + txVersionGroupId = networkParams.SaplingTxVersionGroupId.Value; + } + + else if(isOverwinterActive) + { + txVersion = networkParams.OverwinterTxVersion.Value; + txVersionGroupId = networkParams.OverwinterTxVersionGroupId.Value; + } + + // Misc + isPBaaSActive = false; + this.solver = solver; + + // pbaas minimal merged mining target + if(!string.IsNullOrEmpty(BlockTemplate.MergedBits)) + { + var tmpMergedBits = new Target(BlockTemplate.MergedBits.HexToByteArray()); + blockTargetValue = tmpMergedBits.ToUInt256(); + } + else if(!string.IsNullOrEmpty(BlockTemplate.MergeMineBits)) + { + var tmpMergeMineBits = new Target(BlockTemplate.MergeMineBits.HexToByteArray()); + blockTargetValue = tmpMergeMineBits.ToUInt256(); + } + else if(!string.IsNullOrEmpty(BlockTemplate.Target)) + blockTargetValue = new uint256(BlockTemplate.Target); + else + { + var tmpBits = new Target(BlockTemplate.Bits.HexToByteArray()); + blockTargetValue = tmpBits.ToUInt256(); + } + + previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash + .HexToByteArray() + .ReverseInPlace() + .ToHexString(); + + if(blockTemplate.Subsidy != null) + blockReward = blockTemplate.Subsidy.Miner * BitcoinConstants.SatoshisPerBitcoin; + else + blockReward = BlockTemplate.CoinbaseValue; + + if(networkParams?.PayFundingStream == true) + { + decimal fundingstreamTotal = 0; + fundingstreamTotal = blockTemplate.Subsidy.FundingStreams.Sum(x => x.Value); + blockReward = (blockTemplate.Subsidy.Miner + fundingstreamTotal) * BitcoinConstants.SatoshisPerBitcoin; + } + else if(networkParams?.vOuts == true) + { + blockReward = (decimal) ((blockTemplate.Subsidy.Miner + blockTemplate.Subsidy.Community + blockTemplate.Subsidy.Securenodes + blockTemplate.Subsidy.Supernodes) * BitcoinConstants.SatoshisPerBitcoin); + } + else if(networkParams?.PayFoundersReward == true) + { + var founders = blockTemplate.Subsidy.Founders ?? blockTemplate.Subsidy.Community; + + if(!founders.HasValue) + throw new Exception("Error, founders reward missing for block template"); + + blockReward = (blockTemplate.Subsidy.Miner + founders.Value) * BitcoinConstants.SatoshisPerBitcoin; + } + + rewardFees = blockTemplate.Transactions.Sum(x => x.Fee); + + BuildCoinbase(); + + // build tx hashes + var txHashes = new List { new(coinbaseInitialHash) }; + txHashes.AddRange(BlockTemplate.Transactions.Select(tx => new uint256(tx.Hash.HexToReverseByteArray()))); + + // build merkle root + merkleRoot = MerkleNode.GetRoot(txHashes).Hash.ToBytes().ReverseInPlace(); + merkleRootReversed = merkleRoot.ReverseInPlace(); + merkleRootReversedHex = merkleRootReversed.ToHexString(); + + // misc + var hashReserved = isSaplingActive && !string.IsNullOrEmpty(blockTemplate.FinalSaplingRootHash) ? + blockTemplate.FinalSaplingRootHash.HexToReverseByteArray().ToHexString() : + sha256Empty.ToHexString(); + + string solutionIn = null; + // VerusHash V2.1 activation + if (!string.IsNullOrEmpty(blockTemplate.Solution)) + { + char[] charsToTrim = {'0'}; + solutionIn = blockTemplate.Solution.TrimEnd(charsToTrim); + + if ((solutionIn.Length % 2) == 1) + solutionIn += "0"; + } + + jobParams = new object[] + { + JobId, + BlockTemplate.Version.ReverseByteOrder().ToStringHex8(), + previousBlockHashReversedHex, + merkleRootReversedHex, + hashReserved, + BlockTemplate.CurTime.ReverseByteOrder().ToStringHex8(), + BlockTemplate.Bits.HexToReverseByteArray().ToHexString(), + true, + solutionIn + }; + } + + public override (Share Share, string BlockHex) ProcessShare(StratumConnection worker, string extraNonce2, string nTime, string solution) + { + Contract.RequiresNonNull(worker); + Contract.Requires(!string.IsNullOrEmpty(extraNonce2)); + Contract.Requires(!string.IsNullOrEmpty(nTime)); + Contract.Requires(!string.IsNullOrEmpty(solution)); + + var context = worker.ContextAs(); + + // validate nTime + if(nTime.Length != 8) + throw new StratumException(StratumError.Other, "incorrect size of ntime"); + + var nTimeInt = uint.Parse(nTime.HexToReverseByteArray().ToHexString(), NumberStyles.HexNumber); + // if(nTimeInt < BlockTemplate.CurTime || nTimeInt > ((DateTimeOffset) clock.Now).ToUnixTimeSeconds() + 7200) + // throw new StratumException(StratumError.Other, "ntime out of range"); + + if(nTimeInt != BlockTemplate.CurTime) + throw new StratumException(StratumError.Other, "ntime out of range"); + + var nonce = context.ExtraNonce1 + extraNonce2; + + // validate nonce + if(nonce.Length != 64) + throw new StratumException(StratumError.Other, "incorrect size of extraNonce2"); + + // validate solution + if(solution.Length != (networkParams.SolutionSize + networkParams.SolutionPreambleSize) * 2) + throw new StratumException(StratumError.Other, "incorrect size of solution"); + + // dupe check + if(!RegisterVersucoinSubmit(nonce, solution)) + throw new StratumException(StratumError.DuplicateShare, "duplicate share"); + + // when pbaas activates use block header nonce from daemon, pool/miner can no longer manipulate + if(isPBaaSActive) + { + if(string.IsNullOrEmpty(BlockTemplate.Nonce)) + throw new StratumException(StratumError.Other, "block header nonce not provided by daemon"); + else + nonce = BlockTemplate.Nonce.HexToReverseByteArray().ToHexString(); + + // verify pool nonce presence in solution + var solutionExtraData = solution.Substring(solution.Length - 30); + if(solutionExtraData.IndexOf(context.ExtraNonce1) < 0) + throw new StratumException(StratumError.Other, "invalid solution, pool nonce missing"); + } + + return ProcessVersucoinShareInternal(worker, nonce, nTimeInt, solution); + } + + public override object GetJobParams(bool isNew) + { + jobParams[^2] = isNew; + return jobParams; + } + + #endregion // API-Surface +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Equihash/DaemonResponses/GetBlockTemplateResponse.cs b/src/Miningcore/Blockchain/Equihash/DaemonResponses/GetBlockTemplateResponse.cs index dc889a1ed..fa16c888c 100644 --- a/src/Miningcore/Blockchain/Equihash/DaemonResponses/GetBlockTemplateResponse.cs +++ b/src/Miningcore/Blockchain/Equihash/DaemonResponses/GetBlockTemplateResponse.cs @@ -31,4 +31,17 @@ public class EquihashBlockTemplate : Bitcoin.DaemonResponses.BlockTemplate [JsonProperty("finalsaplingroothash")] public string FinalSaplingRootHash { get; set; } + + // Veruscoin + [JsonProperty("merged_bits")] + public string MergedBits { get; set; } = null; + + [JsonProperty("mergeminebits")] + public string MergeMineBits { get; set; } = null; + + [JsonProperty("solution")] + public string Solution { get; set; } = null; + + [JsonProperty("nonce")] + public string Nonce { get; set; } = null; } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs b/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs index 1d3673360..0c31d25b1 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs @@ -10,6 +10,15 @@ public class EquihashConstants System.Numerics.BigInteger.Parse("0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", NumberStyles.HexNumber); } +public class VeruscoinConstants +{ + public const int SolutionSlice = 6; + public const string HashVersion2b2 = "2b2"; + public const string HashVersion2b1 = "2b1"; + public const string HashVersion2b = "2b"; + public const string HashVersion2 = "2"; +} + public enum ZOperationStatus { Queued, @@ -36,3 +45,8 @@ public static class EquihashCommands public const string ZGetOperationStatus = "z_getoperationstatus"; public const string ZGetOperationResult = "z_getoperationresult"; } + +public static class VeruscoinCommands +{ + public const string SubmitMergedBlock = "submitmergedblock"; +} diff --git a/src/Miningcore/Blockchain/Equihash/EquihashExtraNonceProvider.cs b/src/Miningcore/Blockchain/Equihash/EquihashExtraNonceProvider.cs index 922506770..882f59b7e 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashExtraNonceProvider.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashExtraNonceProvider.cs @@ -6,3 +6,10 @@ public EquihashExtraNonceProvider(string poolId, byte? clusterInstanceId) : base { } } + +public class VeruscoinExtraNonceProvider : ExtraNonceProviderBase +{ + public VeruscoinExtraNonceProvider(string poolId, byte? clusterInstanceId) : base(poolId, 4, clusterInstanceId) + { + } +} diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs index 9d2655e81..cb1753e3e 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJob.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJob.cs @@ -434,7 +434,7 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, public string JobId { get; protected set; } - public (Share Share, string BlockHex) ProcessShare(StratumConnection worker, string extraNonce2, string nTime, string solution) + public virtual (Share Share, string BlockHex) ProcessShare(StratumConnection worker, string extraNonce2, string nTime, string solution) { Contract.RequiresNonNull(worker); Contract.Requires(!string.IsNullOrEmpty(extraNonce2)); @@ -468,7 +468,7 @@ public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, return ProcessShareInternal(worker, nonce, nTimeInt, solution); } - public object GetJobParams(bool isNew) + public virtual object GetJobParams(bool isNew) { jobParams[^1] = isNew; return jobParams; diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 2e4279e5e..d7b9df719 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -1,8 +1,10 @@ +using System.Globalization; using Autofac; using Miningcore.Blockchain.Bitcoin; using Miningcore.Blockchain.Bitcoin.DaemonResponses; using Miningcore.Blockchain.Equihash.Custom.BitcoinGold; using Miningcore.Blockchain.Equihash.Custom.Minexcoin; +using Miningcore.Blockchain.Equihash.Custom.Veruscoin; using Miningcore.Blockchain.Equihash.DaemonResponses; using Miningcore.Configuration; using Miningcore.Contracts; @@ -10,6 +12,7 @@ using Miningcore.Extensions; using Miningcore.JsonRpc; using Miningcore.Messaging; +using Miningcore.Notifications.Messages; using Miningcore.Rpc; using Miningcore.Stratum; using Miningcore.Time; @@ -46,7 +49,7 @@ protected override void PostChainIdentifyConfigure() private async Task> GetBlockTemplateAsync(CancellationToken ct) { var subsidyResponse = await rpc.ExecuteAsync(logger, BitcoinCommands.GetBlockSubsidy, ct); - + var result = await rpc.ExecuteAsync(logger, BitcoinCommands.GetBlockTemplate, ct, extraPoolConfig?.GBTArgs ?? (object) GetBlockTemplateParams()); @@ -54,7 +57,7 @@ private async Task> GetBlockTemplateAsync(Can result.Response.Subsidy = subsidyResponse.Response; else if(subsidyResponse.Error?.Code != (int) BitcoinRPCErrorCode.RPC_METHOD_NOT_FOUND) result = new RpcResponse(null, new JsonRpcError(-1, $"{BitcoinCommands.GetBlockSubsidy} failed", null)); - + return result; } @@ -85,6 +88,9 @@ private EquihashJob CreateJob() case "MNX": return new MinexcoinJob(); + + case "VRSC": + return new VeruscoinJob(); } return new EquihashJob(); @@ -267,8 +273,25 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, if(share.IsBlockCandidate) { logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash}]"); - - var acceptResponse = await SubmitBlockAsync(share, blockHex, ct); + + SubmitResult acceptResponse; + + switch(coin.Symbol) + { + case "VRSC": + // when PBaaS activates we must use the coinbasetxn from daemon to get proper fee pool calculations in coinbase + var solutionVersion = job.BlockTemplate.Solution.Substring(0, 8); + var reversedSolutionVersion = uint.Parse(solutionVersion.HexToReverseByteArray().ToHexString(), NumberStyles.HexNumber); + var isPBaaSActive = (reversedSolutionVersion > 6); + + acceptResponse = await SubmitVeruscoinBlockAsync(share, blockHex, isPBaaSActive, ct); + + break; + default: + acceptResponse = await SubmitBlockAsync(share, blockHex, ct); + + break; + } // is it still a block candidate? share.IsBlockCandidate = acceptResponse.Accepted; @@ -304,7 +327,44 @@ public async ValueTask SubmitShareAsync(StratumConnection worker, return share; } + + protected async Task SubmitVeruscoinBlockAsync(Share share, string blockHex, bool isPBaaSActive, CancellationToken ct) + { + var requestCommand = isPBaaSActive ? VeruscoinCommands.SubmitMergedBlock : BitcoinCommands.SubmitBlock; + var batch = new [] + { + new RpcRequest(requestCommand, new[] { blockHex }), + new RpcRequest(BitcoinCommands.GetBlock, new[] { share.BlockHash }) + }; + + var results = await rpc.ExecuteBatchAsync(logger, ct, batch); + // did submission succeed? + var submitResult = results[0]; + var submitError = submitResult.Error?.Message ?? + submitResult.Error?.Code.ToString(CultureInfo.InvariantCulture) ?? + submitResult.Response?.ToString(); + + if((!isPBaaSActive && !string.IsNullOrEmpty(submitError)) || (isPBaaSActive && !submitError.Contains("accepted"))) + { + logger.Warn(() => $"Block {share.BlockHeight} submission failed with: {submitError}"); + messageBus.SendMessage(new AdminNotification("Block submission failed", $"Pool {poolConfig.Id} {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}failed to submit block {share.BlockHeight}: {submitError}")); + return new SubmitResult(false, null); + } + + // was it accepted? + var acceptResult = results[1]; + var block = acceptResult.Response?.ToObject(); + var accepted = acceptResult.Error == null && block?.Hash == share.BlockHash; + + if(!accepted) + { + logger.Warn(() => $"Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission"); + messageBus.SendMessage(new AdminNotification($"[{share.PoolId.ToUpper()}]-[{share.Source}] Block submission failed", $"[{share.PoolId.ToUpper()}]-[{share.Source}] Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission")); + } + + return new SubmitResult(accepted, block?.Transactions.FirstOrDefault()); + } #endregion // API-Surface } diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs index a9959b560..9f8f993a4 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs @@ -7,6 +7,7 @@ using Microsoft.IO; using Miningcore.Blockchain.Bitcoin; using Miningcore.Blockchain.Equihash.Configuration; +using Miningcore.Blockchain.Equihash.Custom.Veruscoin; using Miningcore.Configuration; using Miningcore.Extensions; using Miningcore.JsonRpc; @@ -59,10 +60,21 @@ public override void Configure(PoolConfig pc, ClusterConfig cc) throw new PoolStartupException("Pool z-address is not configured", pc.Id); } + private EquihashJobManager createEquihashExtraNonceProvider() + { + switch(coin.Symbol) + { + case "VRSC": + return ctx.Resolve(new TypedParameter(typeof(IExtraNonceProvider), new VeruscoinExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); + + default: + return ctx.Resolve(new TypedParameter(typeof(IExtraNonceProvider), new EquihashExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); + } + } + protected override async Task SetupJobManager(CancellationToken ct) { - manager = ctx.Resolve( - new TypedParameter(typeof(IExtraNonceProvider), new EquihashExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); + manager = ctx.Resolve(new TypedParameter(typeof(IExtraNonceProvider), new EquihashExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); manager.Configure(poolConfig, clusterConfig); @@ -380,7 +392,7 @@ public override double HashrateFromShares(double shares, double interval) { var multiplier = BitcoinConstants.Pow2x32; var result = shares * multiplier / interval / 1000000 * 2; - + result /= hashrateDivisor; return result; } diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 9392d47b4..c851dfe6c 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -16,6 +16,9 @@ namespace Miningcore.Configuration; public enum CoinFamily { + [EnumMember(Value = "beam")] + Beam, + [EnumMember(Value = "bitcoin")] Bitcoin, @@ -130,6 +133,7 @@ public abstract partial class CoinTemplate [JsonIgnore] public static readonly Dictionary Families = new() { + {CoinFamily.Beam, typeof(BeamCoinTemplate)}, {CoinFamily.Bitcoin, typeof(BitcoinTemplate)}, {CoinFamily.Equihash, typeof(EquihashCoinTemplate)}, {CoinFamily.Conceal, typeof(ConcealCoinTemplate)}, @@ -139,6 +143,10 @@ public abstract partial class CoinTemplate }; } +public partial class BeamCoinTemplate : CoinTemplate +{ +} + public enum BitcoinSubfamily { [EnumMember(Value = "none")] @@ -186,9 +194,6 @@ public class BitcoinNetworkParams [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasMasterNodes { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool HasSmartNodes { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasBrokenSendMany { get; set; } = false; diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index d7c783306..3bfb710f4 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -25,6 +25,18 @@ public T As() where T : CoinTemplate public string Source { get; set; } } +public partial class BeamCoinTemplate +{ + #region Overrides of CoinTemplate + + public override string GetAlgorithmName() + { + return "BeamHash"; + } + + #endregion +} + public partial class BitcoinTemplate { public BitcoinTemplate() diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/MinotaurX.cs b/src/Miningcore/Crypto/Hashing/Algorithms/MinotaurX.cs new file mode 100644 index 000000000..cb71d6583 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/MinotaurX.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("minotaurx")] +public unsafe class MinotaurX : 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.minotaurx(input, output); + } + } + } +} diff --git a/src/Miningcore/Native/BeamHash.cs b/src/Miningcore/Native/BeamHash.cs new file mode 100644 index 000000000..5e0bd0d08 --- /dev/null +++ b/src/Miningcore/Native/BeamHash.cs @@ -0,0 +1,81 @@ +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 BeamHash +{ + /// + /// Verify an BeamHash solution + /// + /// header (32 bytes) + /// nonce (8 bytes) + /// beamhash solution without size-preamble + /// beamhash pow + /// boolean + [DllImport("libbeamhash", EntryPoint = "beamhash_verify_export", CallingConvention = CallingConvention.Cdecl)] + public static extern bool beamhash_verify(byte* header, int header_length, byte* solution, int solution_length, byte* nonce, int nonce_length, int pow); + + private static int maxThreads = 1; + + public static int MaxThreads + { + get => maxThreads; + set + { + if(sem.IsValueCreated) + throw new InvalidOperationException("Too late: semaphore already created"); + + maxThreads = value; + } + } + + internal static IMessageBus messageBus; + + protected static readonly Lazy sem = new(() => + new Semaphore(maxThreads, maxThreads)); + + /// + /// Verify an BeamHash solution + /// + /// header (32 bytes) + /// nonce (8 bytes) + /// beamhash solution without size-preamble + /// beamhash pow + /// boolean + public bool Verify(ReadOnlySpan header, ReadOnlySpan solution, ReadOnlySpan nonce, int pow) + { + var sw = Stopwatch.StartNew(); + + try + { + sem.Value.WaitOne(); + + fixed (byte* h = header) + { + fixed (byte* s = solution) + { + fixed (byte* n = nonce) + { + var result = beamhash_verify(h, header.Length, s, solution.Length, n, nonce.Length, pow); + + messageBus?.SendTelemetry("Beamhash-" + pow, TelemetryCategory.Hash, sw.Elapsed, result); + + return result; + } + } + } + } + + finally + { + sem.Value.Release(); + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Native/Multihash.cs b/src/Miningcore/Native/Multihash.cs index 8ebb2294d..96ff81619 100644 --- a/src/Miningcore/Native/Multihash.cs +++ b/src/Miningcore/Native/Multihash.cs @@ -150,4 +150,7 @@ 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); } diff --git a/src/Miningcore/Native/Verushash.cs b/src/Miningcore/Native/Verushash.cs new file mode 100644 index 000000000..0fb10949e --- /dev/null +++ b/src/Miningcore/Native/Verushash.cs @@ -0,0 +1,60 @@ +using System.Runtime.InteropServices; +using Miningcore.Blockchain.Equihash; +using Miningcore.Contracts; +using Miningcore.Native; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Native; + +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 = "verushash2b1_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void verushash2b1(byte* input, byte* output, int input_length); + + [DllImport("libverushash", EntryPoint = "verushash2b_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void verushash2b(byte* input, byte* output, int input_length); + + [DllImport("libverushash", EntryPoint = "verushash2_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void verushash2(byte* input, byte* output, int input_length); + + [DllImport("libverushash", EntryPoint = "verushash_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void verushash(byte* input, byte* output, int input_length); + + public void Digest(ReadOnlySpan data, Span result, string version = null, params object[] extra) + { + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + switch(version) + { + case VeruscoinConstants.HashVersion2b2: + verushash2b2(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; + } + } + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Stratum/StratumConnection.cs b/src/Miningcore/Stratum/StratumConnection.cs index 9748d91c1..d2af1003d 100644 --- a/src/Miningcore/Stratum/StratumConnection.cs +++ b/src/Miningcore/Stratum/StratumConnection.cs @@ -206,6 +206,12 @@ public Task NotifyAsync(JsonRpcRequest request) { return SendAsync(request); } + + // Beam stratum API: https://github.com/BeamMW/beam/wiki/Beam-mining-protocol-API-(Stratum) + public Task NotifyAsync(object request) + { + return SendAsync(request); + } public void Disconnect() { diff --git a/src/Miningcore/build-libs-linux.sh b/src/Miningcore/build-libs-linux.sh index 5af3bab26..fbf0f9d27 100755 --- a/src/Miningcore/build-libs-linux.sh +++ b/src/Miningcore/build-libs-linux.sh @@ -23,11 +23,13 @@ HAVE_AVX512F=$(../Native/check_cpu.sh avx512f && echo -DHAVE_AVX512F || echo) export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_AVX $HAVE_AVX2 $HAVE_AVX512F" (cd ../Native/libmultihash && make clean && make) && mv ../Native/libmultihash/libmultihash.so "$OutDir" +(cd ../Native/libbeamhash && make clean && make) && mv ../Native/libbeamhash/libbeamhash.so "$OutDir" (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/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" +(cd ../Native/libverushash && make clean && make) && mv ../Native/libverushash/libverushash.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") diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index bc624a715..5b7e682fb 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -2169,7 +2169,6 @@ }, "hasFounderFee": true, "hasMasterNodes": true, - "hasSmartNodes": true, "foundersRewardAddress": [ "RTtyQU6DoSuNWetT4WUem5qXP5jNYGpwat" ], @@ -2247,6 +2246,28 @@ "explorerTxLink": "https://explorer.novochain.ovh/tx/{0}", "explorerAccountLink": "https://explorer.novochain.ovh/address/{0}" }, + "pulsar": { + "name": "Pulsar", + "symbol": "PLSR", + "family": "bitcoin", + "website": "https://pulsarcoin.org/", + "market": "https://www.coingecko.com/en/coins/pulsar-coin", + "twitter": "https://www.twitter.com/PulsarCoin", + "discord": "https://discord.gg/7feEVsvDj9", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "minotaurx" + }, + "blockHasher": { + "hash": "reverse", + "args": [ { "hash": "minotaurx" } ] + }, + "explorerBlockLink": "https://explorer.pulsarcoin.org/block/$height$", + "explorerTxLink": "https://explorer.pulsarcoin.org/tx/{0}", + "explorerAccountLink": "https://explorer.pulsarcoin.org/address/{0}" + }, "bitoreum": { "name": "Bitoreum", "canonicalName": "Bitoreum", @@ -2272,7 +2293,6 @@ }, "hasFounderFee": true, "hasMasterNodes": true, - "hasSmartNodes": true, "foundersRewardAddress": [ "BanxgMPcMpXnuWQ2ogfQqEkwwVtjhAhXBR" ], @@ -2770,7 +2790,6 @@ }, "hasFounderFee": true, "hasMasterNodes": true, - "hasSmartNodes": true, "shareMultiplier": 65536, "explorerBlockLink": "http://rtm.timyg.org:6950/block/$height$", "explorerTxLink": "http://rtm.timyg.org:6950/tx/{0}", @@ -3359,7 +3378,6 @@ }, "hasFounderFee": true, "hasMasterNodes": true, - "hasSmartNodes": true, "shareMultiplier": 65536, "explorerBlockLink": "https://explorer.yerbas.org/block/$height$", "explorerTxLink": "https://explorer.yerbas.org/tx/{0}", @@ -3732,7 +3750,7 @@ "overwinterActivationHeight": 1, "overwinterTxVersion": 3, "overwinterTxVersionGroupId": 63210096, - "saplingActivationHeight": 1, + "saplingActivationHeight": 227520, "saplingTxVersion": 4, "saplingTxVersionGroupId": 2301567109 }, @@ -3749,7 +3767,13 @@ ] }, "coinbaseTxNetwork": "testnet", - "payFoundersReward": false + "payFoundersReward": false, + "overwinterActivationHeight": 1, + "overwinterTxVersion": 3, + "overwinterTxVersionGroupId": 63210096, + "saplingActivationHeight": 120, + "saplingTxVersion": 4, + "saplingTxVersionGroupId": 2301567109 }, "regtest": { "diff1": "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -3758,8 +3782,8 @@ "solver": { "hash": "equihash", "args": [ - 200, - 9, + 48, + 5, "Verushash" ] }, @@ -4219,6 +4243,19 @@ "explorerTxLink": "http://explorer.zensystem.io/transactions/{0}", "explorerAccountLink": "http://explorer.zensystem.io/accounts/{0}" }, + "beam": { + "name": "Beam", + "canonicalName": "Beam", + "symbol": "BEAM", + "family": "beam", + "website": "https://beam.mw/", + "market": "", + "twitter": "https://twitter.com/beamprivacy", + "telegram": "https://t.me/BeamPrivacy", + "discord": "http://discord.gg/BHZvAhg", + "explorerBlockLink": "https://explorer.beam.mw/block/$hash$", + "explorerTxLink": "https://explorer.beam.mw/?searched_by={0}" + }, "monero": { "name": "Monero", "canonicalName": "Monero", diff --git a/src/Native/libbeamhash/Makefile b/src/Native/libbeamhash/Makefile new file mode 100644 index 000000000..96b1800a0 --- /dev/null +++ b/src/Native/libbeamhash/Makefile @@ -0,0 +1,16 @@ +CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable $(CPU_FLAGS) $(HAVE_FEATURE) +CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS) $(HAVE_FEATURE) +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 + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libbeamhash/arith_uint256.cpp b/src/Native/libbeamhash/arith_uint256.cpp new file mode 100644 index 000000000..2e6136357 --- /dev/null +++ b/src/Native/libbeamhash/arith_uint256.cpp @@ -0,0 +1,260 @@ +// 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 new file mode 100644 index 000000000..23c06aa6f --- /dev/null +++ b/src/Native/libbeamhash/beam/core/common.h @@ -0,0 +1 @@ +#include "../utility/common.h" diff --git a/src/Native/libbeamhash/beam/core/difficulty.cpp b/src/Native/libbeamhash/beam/core/difficulty.cpp new file mode 100644 index 000000000..d40d9ab84 --- /dev/null +++ b/src/Native/libbeamhash/beam/core/difficulty.cpp @@ -0,0 +1,234 @@ +// 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 new file mode 100644 index 000000000..59fce667b --- /dev/null +++ b/src/Native/libbeamhash/beam/core/difficulty.h @@ -0,0 +1,56 @@ +// 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 new file mode 100644 index 000000000..313b7d2d5 --- /dev/null +++ b/src/Native/libbeamhash/beam/core/uintBig.cpp @@ -0,0 +1,346 @@ +// 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 new file mode 100644 index 000000000..9492e88c1 --- /dev/null +++ b/src/Native/libbeamhash/beam/core/uintBig.h @@ -0,0 +1,360 @@ +// 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 new file mode 100644 index 000000000..d56e579e8 --- /dev/null +++ b/src/Native/libbeamhash/beam/utility/common.cpp @@ -0,0 +1,461 @@ +// 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 new file mode 100644 index 000000000..34083724c --- /dev/null +++ b/src/Native/libbeamhash/beam/utility/common.h @@ -0,0 +1,234 @@ +// 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/beamhashverify.cpp b/src/Native/libbeamhash/beamhashverify.cpp new file mode 100644 index 000000000..6ac56a7f7 --- /dev/null +++ b/src/Native/libbeamhash/beamhashverify.cpp @@ -0,0 +1,44 @@ +#include "beamhashverify.h" +#include +#include "crypto/beamHashIII.h" +#include "crypto/equihashR.h" +#include "beam/core/difficulty.h" +#include "beam/core/uintBig.h" + +#include + +#include + +bool verifyBH(const char *hdr, const char *nonceBuffer, const std::vector &soln, int pow){ + + 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"); + } + + return isValid; +} \ No newline at end of file diff --git a/src/Native/libbeamhash/beamhashverify.h b/src/Native/libbeamhash/beamhashverify.h new file mode 100644 index 000000000..1632d8064 --- /dev/null +++ b/src/Native/libbeamhash/beamhashverify.h @@ -0,0 +1,24 @@ +#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 + +#ifdef __cplusplus +extern "C" { +#endif + +bool verifyBH(const char*, const char*, const std::vector&, int pow); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/Native/libbeamhash/crypto/beamHashIII.cpp b/src/Native/libbeamhash/crypto/beamHashIII.cpp new file mode 100644 index 000000000..bf1d4c523 --- /dev/null +++ b/src/Native/libbeamhash/crypto/beamHashIII.cpp @@ -0,0 +1,379 @@ + +#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 new file mode 100644 index 000000000..2ecab2d62 --- /dev/null +++ b/src/Native/libbeamhash/crypto/beamHashIII.h @@ -0,0 +1,59 @@ +// 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 new file mode 100644 index 000000000..73e556892 --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/ref/Makefile @@ -0,0 +1,14 @@ +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/blake/ref/blake2-impl.h b/src/Native/libbeamhash/crypto/blake/ref/blake2-impl.h new file mode 100644 index 000000000..c1df82e0c --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/ref/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 )((( uint32_t )( p[0] ) << 0) | + (( uint32_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/libbeamhash/crypto/blake/ref/blake2.h new file mode 100644 index 000000000..0b3296a9c --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/ref/blake2.h @@ -0,0 +1,195 @@ +/* + 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_H +#define BLAKE2_H + +#include +#include + +#if defined(_MSC_VER) +#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) +#else +#define BLAKE2_PACKED(x) x __attribute__((packed)) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + enum blake2b_constant + { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + + typedef struct blake2s_state__ + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2s_state; + + typedef struct blake2b_state__ + { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2b_state; + + typedef struct blake2sp_state__ + { + blake2s_state S[8][1]; + blake2s_state R[1]; + uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2sp_state; + + typedef struct blake2bp_state__ + { + blake2b_state S[4][1]; + blake2b_state R[1]; + uint8_t buf[4 * BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2bp_state; + + + BLAKE2_PACKED(struct blake2s_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ + }); + + typedef struct blake2s_param__ blake2s_param; + + BLAKE2_PACKED(struct blake2b_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint32_t xof_length; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ + }); + + typedef struct blake2b_param__ blake2b_param; + + typedef struct blake2xs_state__ + { + blake2s_state S[1]; + blake2s_param P[1]; + } blake2xs_state; + + typedef struct blake2xb_state__ + { + blake2b_state S[1]; + blake2b_param P[1]; + } blake2xb_state; + + /* 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) + }; + + /* Streaming API */ + int blake2s_init( blake2s_state *S, size_t outlen ); + int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const void *in, size_t inlen ); + int blake2s_final( blake2s_state *S, void *out, size_t outlen ); + + int blake2b_init( blake2b_state *S, size_t outlen ); + int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); + int blake2b_update( blake2b_state *S, const void *in, size_t inlen ); + int blake2b_final( blake2b_state *S, void *out, size_t outlen ); + + int blake2sp_init( blake2sp_state *S, size_t outlen ); + int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen ); + int blake2sp_final( blake2sp_state *S, void *out, size_t outlen ); + + int blake2bp_init( blake2bp_state *S, size_t outlen ); + int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen ); + int blake2bp_final( blake2bp_state *S, void *out, size_t outlen ); + + /* Variable output length API */ + int blake2xs_init( blake2xs_state *S, const size_t outlen ); + int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ); + int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ); + int blake2xs_final(blake2xs_state *S, void *out, size_t outlen); + + int blake2xb_init( blake2xb_state *S, const size_t outlen ); + int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen ); + int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ); + int blake2xb_final(blake2xb_state *S, void *out, size_t outlen); + + /* Simple API */ + int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + /* This is simply an alias for blake2b */ + int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/Native/libbeamhash/crypto/blake/ref/blake2b-ref.c b/src/Native/libbeamhash/crypto/blake/ref/blake2b-ref.c new file mode 100644 index 000000000..cd38b1ba0 --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/ref/blake2b-ref.c @@ -0,0 +1,379 @@ +/* + 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. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + + +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2b_init0( blake2b_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2b_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + const uint8_t *p = ( const uint8_t * )( P ); + size_t i; + + blake2b_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; + return 0; +} + + + +int blake2b_init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + uint64_t m[16]; + uint64_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load64( block + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2b_final( blake2b_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + secure_zero_memory(buffer, sizeof(buffer)); + return 0; +} + +/* inlen, at least, should be uint64_t. Others can be size_t. */ +int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2b_init( S, outlen ) < 0 ) return -1; + } + + blake2b_update( S, ( const uint8_t * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; +} + +int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { + return blake2b(out, outlen, in, inlen, key, keylen); +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2B_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2b_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2b_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2-config.h b/src/Native/libbeamhash/crypto/blake/sse/blake2-config.h new file mode 100644 index 000000000..ef6fd6b4c --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2-config.h @@ -0,0 +1,83 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2_CONFIG_H__ +#define __BLAKE2_CONFIG_H__ + +#if defined(_M_IX86_FP) + #if _M_IX86_FP == 2 + #define HAVE_SSE2 + #ifndef HAVE_AVX + #define HAVE_AVX + #endif + #endif +#elif defined(_M_AMD64) || defined(_M_X64) + #define HAVE_SSSE3 +#endif + +// These don't work everywhere +#if defined(__SSE2__) +#define HAVE_SSE2 +#endif + +#if defined(__SSSE3__) +#define HAVE_SSSE3 +#endif + +#if defined(__SSE4_1__) +#define HAVE_SSE41 +#endif + +#if defined(__AVX__) || defined(__AVX2__) +#define HAVE_AVX +#endif + +#if defined(__XOP__) +#define HAVE_XOP +#endif + + +#ifdef HAVE_AVX2 +#ifndef HAVE_AVX +#define HAVE_AVX +#endif +#endif + +#ifdef HAVE_XOP +#ifndef HAVE_AVX +#define HAVE_AVX +#endif +#endif + +#ifdef HAVE_AVX +#ifndef HAVE_SSE41 +#define HAVE_SSE41 +#endif +#endif + +#ifdef HAVE_SSE41 +#ifndef HAVE_SSSE3 +#define HAVE_SSSE3 +#endif +#endif + +#ifdef HAVE_SSSE3 +#define HAVE_SSE2 +#endif + +#if !defined(HAVE_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/crypto/blake/sse/blake2-impl.h new file mode 100644 index 000000000..16219dbcb --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2-impl.h @@ -0,0 +1,136 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2_IMPL_H__ +#define __BLAKE2_IMPL_H__ + +#include + +static 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; + uint32_t w = *p++; + w |= ( uint32_t )( *p++ ) << 8; + w |= ( uint32_t )( *p++ ) << 16; + w |= ( uint32_t )( *p++ ) << 24; + return w; +#endif +} + +static 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; + uint64_t w = *p++; + w |= ( uint64_t )( *p++ ) << 8; + w |= ( uint64_t )( *p++ ) << 16; + w |= ( uint64_t )( *p++ ) << 24; + w |= ( uint64_t )( *p++ ) << 32; + w |= ( uint64_t )( *p++ ) << 40; + w |= ( uint64_t )( *p++ ) << 48; + w |= ( uint64_t )( *p++ ) << 56; + return w; +#endif +} + +static 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++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static 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++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static inline uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + uint64_t w = *p++; + w |= ( uint64_t )( *p++ ) << 8; + w |= ( uint64_t )( *p++ ) << 16; + w |= ( uint64_t )( *p++ ) << 24; + w |= ( uint64_t )( *p++ ) << 32; + w |= ( uint64_t )( *p++ ) << 40; + return w; +} + +static inline void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +} + +static inline uint32_t rotl32( const uint32_t w, const unsigned c ) +{ + return ( w << c ) | ( w >> ( 32 - c ) ); +} + +static inline uint64_t rotl64( const uint64_t w, const unsigned c ) +{ + return ( w << c ) | ( w >> ( 64 - c ) ); +} + +static inline uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static inline uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static inline void secure_zero_memory( void *v, size_t n ) +{ + volatile uint8_t *p = ( volatile uint8_t * )v; + while( n-- ) *p++ = 0; +} + +#endif + diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2-round.h b/src/Native/libbeamhash/crypto/blake/sse/blake2-round.h new file mode 100644 index 000000000..400ed2034 --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2-round.h @@ -0,0 +1,85 @@ +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \ + : (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c)))) + +#define G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + row1l = _mm_add_epi64(row1l, row2l); \ + row1h = _mm_add_epi64(row1h, row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -32); \ + row4h = _mm_roti_epi64(row4h, -32); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -24); \ + row2h = _mm_roti_epi64(row2h, -24); \ + +#define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + row1l = _mm_add_epi64(row1l, row2l); \ + row1h = _mm_add_epi64(row1h, row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -16); \ + row4h = _mm_roti_epi64(row4h, -16); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -63); \ + row2h = _mm_roti_epi64(row2h, -63); \ + +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2h, row2l, 8); \ + t1 = _mm_alignr_epi8(row2l, row2h, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4h, row4l, 8); \ + t1 = _mm_alignr_epi8(row4l, row4h, 8); \ + row4l = t1; \ + row4h = t0; + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2l, row2h, 8); \ + t1 = _mm_alignr_epi8(row2h, row2l, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4l, row4h, 8); \ + t1 = _mm_alignr_epi8(row4h, row4l, 8); \ + row4l = t1; \ + row4h = t0; + +#define BLAKE2_ROUND(row1l,row1h,row2l,row2h,row3l,row3h,row4l,row4h) \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + \ + DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + \ + UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2.h b/src/Native/libbeamhash/crypto/blake/sse/blake2.h new file mode 100644 index 000000000..397fef422 --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2.h @@ -0,0 +1,162 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2_H__ +#define __BLAKE2_H__ + +#include +#include + +#if defined(_MSC_VER) +#define ALIGN(x) __declspec(align(x)) +#else +#define ALIGN(x) __attribute__ ((__aligned__(x))) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + enum blake2b_constant + { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + +#ifdef _MSC_VER +# pragma warning (disable: 4324) // structure was padded due to alignment specifier +#endif // _MSC_VER +#pragma pack(push, 1) + typedef struct __blake2s_param + { + uint8_t digest_length; // 1 + uint8_t key_length; // 2 + uint8_t fanout; // 3 + uint8_t depth; // 4 + uint32_t leaf_length; // 8 + uint8_t node_offset[6];// 14 + uint8_t node_depth; // 15 + uint8_t inner_length; // 16 + // uint8_t reserved[0]; + uint8_t salt[BLAKE2S_SALTBYTES]; // 24 + uint8_t personal[BLAKE2S_PERSONALBYTES]; // 32 + } blake2s_param; + + ALIGN( 64 ) typedef struct __blake2s_state + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[2 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + uint8_t last_node; + } blake2s_state; + + typedef struct __blake2b_param + { + uint8_t digest_length; // 1 + uint8_t key_length; // 2 + uint8_t fanout; // 3 + uint8_t depth; // 4 + uint32_t leaf_length; // 8 + uint64_t node_offset; // 16 + uint8_t node_depth; // 17 + uint8_t inner_length; // 18 + uint8_t reserved[14]; // 32 + uint8_t salt[BLAKE2B_SALTBYTES]; // 48 + uint8_t personal[BLAKE2B_PERSONALBYTES]; // 64 + } blake2b_param; + + ALIGN( 64 ) typedef struct __blake2b_state + { + uint64_t h[8]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + uint16_t counter; + uint8_t buflen; + uint8_t lastblock; + } blake2b_state; + + ALIGN( 64 ) typedef struct __blake2sp_state + { + blake2s_state S[8][1]; + blake2s_state R[1]; + uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + } blake2sp_state; + + ALIGN( 64 ) typedef struct __blake2bp_state + { + blake2b_state S[4][1]; + blake2b_state R[1]; + uint8_t buf[4 * BLAKE2B_BLOCKBYTES]; + size_t buflen; + } blake2bp_state; +#pragma pack(pop) +#ifdef _MSC_VER +# pragma warning (default: 4324) +#endif // _MSC_VER + + // Streaming API + int blake2s_init( blake2s_state *S, const uint8_t outlen ); + int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen ); + int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen ); + + int blake2b_init( blake2b_state *S, const uint8_t outlen ); + int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); + int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen ); + int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen ); + + int blake2sp_init( blake2sp_state *S, const uint8_t outlen ); + int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen ); + int blake2sp_final( blake2sp_state *S, uint8_t *out, uint8_t outlen ); + + int blake2bp_init( blake2bp_state *S, const uint8_t outlen ); + int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ); + int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen ); + int blake2bp_final( blake2bp_state *S, uint8_t *out, uint8_t outlen ); + + // Simple API + int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + int blake2b_long(uint8_t *out, const void *in, const uint32_t outlen, const uint64_t inlen); + + int blake2sp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + int blake2bp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ); + + static inline int blake2( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ) + { + return blake2b( out, in, key, outlen, inlen, keylen ); + } + +#if defined(__cplusplus) +} +#endif + +#endif + diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse2.h b/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse2.h new file mode 100644 index 000000000..1ba153c87 --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse2.h @@ -0,0 +1,68 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2B_LOAD_SSE2_H__ +#define __BLAKE2B_LOAD_SSE2_H__ + +#define LOAD_MSG_0_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_0_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_0_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_0_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_1_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_1_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_1_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_1_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7) +#define LOAD_MSG_2_1(b0, b1) b0 = _mm_set_epi64x(m12, m11); b1 = _mm_set_epi64x(m15, m5) +#define LOAD_MSG_2_2(b0, b1) b0 = _mm_set_epi64x(m0, m8); b1 = _mm_set_epi64x(m13, m2) +#define LOAD_MSG_2_3(b0, b1) b0 = _mm_set_epi64x(m3, m10); b1 = _mm_set_epi64x(m9, m7) +#define LOAD_MSG_2_4(b0, b1) b0 = _mm_set_epi64x(m6, m14); b1 = _mm_set_epi64x(m4, m1) +#define LOAD_MSG_3_1(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m13) +#define LOAD_MSG_3_2(b0, b1) b0 = _mm_set_epi64x(m1, m9); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_3_3(b0, b1) b0 = _mm_set_epi64x(m5, m2); b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_3_4(b0, b1) b0 = _mm_set_epi64x(m10, m6); b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_4_1(b0, b1) b0 = _mm_set_epi64x(m5, m9); b1 = _mm_set_epi64x(m10, m2) +#define LOAD_MSG_4_2(b0, b1) b0 = _mm_set_epi64x(m7, m0); b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_4_3(b0, b1) b0 = _mm_set_epi64x(m11, m14); b1 = _mm_set_epi64x(m3, m6) +#define LOAD_MSG_4_4(b0, b1) b0 = _mm_set_epi64x(m12, m1); b1 = _mm_set_epi64x(m13, m8) +#define LOAD_MSG_5_1(b0, b1) b0 = _mm_set_epi64x(m6, m2); b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_5_2(b0, b1) b0 = _mm_set_epi64x(m10, m12); b1 = _mm_set_epi64x(m3, m11) +#define LOAD_MSG_5_3(b0, b1) b0 = _mm_set_epi64x(m7, m4); b1 = _mm_set_epi64x(m1, m15) +#define LOAD_MSG_5_4(b0, b1) b0 = _mm_set_epi64x(m5, m13); b1 = _mm_set_epi64x(m9, m14) +#define LOAD_MSG_6_1(b0, b1) b0 = _mm_set_epi64x(m1, m12); b1 = _mm_set_epi64x(m4, m14) +#define LOAD_MSG_6_2(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m10, m13) +#define LOAD_MSG_6_3(b0, b1) b0 = _mm_set_epi64x(m6, m0); b1 = _mm_set_epi64x(m8, m9) +#define LOAD_MSG_6_4(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m2) +#define LOAD_MSG_7_1(b0, b1) b0 = _mm_set_epi64x(m7, m13); b1 = _mm_set_epi64x(m3, m12) +#define LOAD_MSG_7_2(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m9, m1) +#define LOAD_MSG_7_3(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m2, m8) +#define LOAD_MSG_7_4(b0, b1) b0 = _mm_set_epi64x(m4, m0); b1 = _mm_set_epi64x(m10, m6) +#define LOAD_MSG_8_1(b0, b1) b0 = _mm_set_epi64x(m14, m6); b1 = _mm_set_epi64x(m0, m11) +#define LOAD_MSG_8_2(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m8, m3) +#define LOAD_MSG_8_3(b0, b1) b0 = _mm_set_epi64x(m13, m12); b1 = _mm_set_epi64x(m10, m1) +#define LOAD_MSG_8_4(b0, b1) b0 = _mm_set_epi64x(m7, m2); b1 = _mm_set_epi64x(m5, m4) +#define LOAD_MSG_9_1(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m1, m7) +#define LOAD_MSG_9_2(b0, b1) b0 = _mm_set_epi64x(m4, m2); b1 = _mm_set_epi64x(m5, m6) +#define LOAD_MSG_9_3(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m13, m3) +#define LOAD_MSG_9_4(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m0, m12) +#define LOAD_MSG_10_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_10_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_10_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_10_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_11_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_11_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_11_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_11_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7) + + +#endif + diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse41.h b/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse41.h new file mode 100644 index 000000000..f6c1bc839 --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2b-load-sse41.h @@ -0,0 +1,402 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2B_LOAD_SSE41_H__ +#define __BLAKE2B_LOAD_SSE41_H__ + +#define LOAD_MSG_0_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m1); \ +b1 = _mm_unpacklo_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_0_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m0, m1); \ +b1 = _mm_unpackhi_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_0_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m5); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_0_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m5); \ +b1 = _mm_unpackhi_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_1_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m2); \ +b1 = _mm_unpackhi_epi64(m4, m6); \ +} while(0) + + +#define LOAD_MSG_1_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_alignr_epi8(m3, m7, 8); \ +} while(0) + + +#define LOAD_MSG_1_3(b0, b1) \ +do \ +{ \ +b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ +b1 = _mm_unpackhi_epi64(m5, m2); \ +} while(0) + + +#define LOAD_MSG_1_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m1); \ +b1 = _mm_unpackhi_epi64(m3, m1); \ +} while(0) + + +#define LOAD_MSG_2_1(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m6, m5, 8); \ +b1 = _mm_unpackhi_epi64(m2, m7); \ +} while(0) + + +#define LOAD_MSG_2_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m0); \ +b1 = _mm_blend_epi16(m1, m6, 0xF0); \ +} while(0) + + +#define LOAD_MSG_2_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m5, m1, 0xF0); \ +b1 = _mm_unpackhi_epi64(m3, m4); \ +} while(0) + + +#define LOAD_MSG_2_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m3); \ +b1 = _mm_alignr_epi8(m2, m0, 8); \ +} while(0) + + +#define LOAD_MSG_3_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m3, m1); \ +b1 = _mm_unpackhi_epi64(m6, m5); \ +} while(0) + + +#define LOAD_MSG_3_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m0); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_3_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m1, m2, 0xF0); \ +b1 = _mm_blend_epi16(m2, m7, 0xF0); \ +} while(0) + + +#define LOAD_MSG_3_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m3, m5); \ +b1 = _mm_unpacklo_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_4_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m2); \ +b1 = _mm_unpacklo_epi64(m1, m5); \ +} while(0) + + +#define LOAD_MSG_4_2(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m0, m3, 0xF0); \ +b1 = _mm_blend_epi16(m2, m7, 0xF0); \ +} while(0) + + +#define LOAD_MSG_4_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m7, m5, 0xF0); \ +b1 = _mm_blend_epi16(m3, m1, 0xF0); \ +} while(0) + + +#define LOAD_MSG_4_4(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m6, m0, 8); \ +b1 = _mm_blend_epi16(m4, m6, 0xF0); \ +} while(0) + + +#define LOAD_MSG_5_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m1, m3); \ +b1 = _mm_unpacklo_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_5_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m5); \ +b1 = _mm_unpackhi_epi64(m5, m1); \ +} while(0) + + +#define LOAD_MSG_5_3(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m2, m3, 0xF0); \ +b1 = _mm_unpackhi_epi64(m7, m0); \ +} while(0) + + +#define LOAD_MSG_5_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m6, m2); \ +b1 = _mm_blend_epi16(m7, m4, 0xF0); \ +} while(0) + + +#define LOAD_MSG_6_1(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m6, m0, 0xF0); \ +b1 = _mm_unpacklo_epi64(m7, m2); \ +} while(0) + + +#define LOAD_MSG_6_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m2, m7); \ +b1 = _mm_alignr_epi8(m5, m6, 8); \ +} while(0) + + +#define LOAD_MSG_6_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m3); \ +b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1,0,3,2)); \ +} while(0) + + +#define LOAD_MSG_6_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m3, m1); \ +b1 = _mm_blend_epi16(m1, m5, 0xF0); \ +} while(0) + + +#define LOAD_MSG_7_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m6, m3); \ +b1 = _mm_blend_epi16(m6, m1, 0xF0); \ +} while(0) + + +#define LOAD_MSG_7_2(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m7, m5, 8); \ +b1 = _mm_unpackhi_epi64(m0, m4); \ +} while(0) + + +#define LOAD_MSG_7_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m2, m7); \ +b1 = _mm_unpacklo_epi64(m4, m1); \ +} while(0) + + +#define LOAD_MSG_7_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m2); \ +b1 = _mm_unpacklo_epi64(m3, m5); \ +} while(0) + + +#define LOAD_MSG_8_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m3, m7); \ +b1 = _mm_alignr_epi8(m0, m5, 8); \ +} while(0) + + +#define LOAD_MSG_8_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m7, m4); \ +b1 = _mm_alignr_epi8(m4, m1, 8); \ +} while(0) + + +#define LOAD_MSG_8_3(b0, b1) \ +do \ +{ \ +b0 = m6; \ +b1 = _mm_alignr_epi8(m5, m0, 8); \ +} while(0) + + +#define LOAD_MSG_8_4(b0, b1) \ +do \ +{ \ +b0 = _mm_blend_epi16(m1, m3, 0xF0); \ +b1 = m2; \ +} while(0) + + +#define LOAD_MSG_9_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_unpackhi_epi64(m3, m0); \ +} while(0) + + +#define LOAD_MSG_9_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m1, m2); \ +b1 = _mm_blend_epi16(m3, m2, 0xF0); \ +} while(0) + + +#define LOAD_MSG_9_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m7, m4); \ +b1 = _mm_unpackhi_epi64(m1, m6); \ +} while(0) + + +#define LOAD_MSG_9_4(b0, b1) \ +do \ +{ \ +b0 = _mm_alignr_epi8(m7, m5, 8); \ +b1 = _mm_unpacklo_epi64(m6, m0); \ +} while(0) + + +#define LOAD_MSG_10_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m0, m1); \ +b1 = _mm_unpacklo_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_10_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m0, m1); \ +b1 = _mm_unpackhi_epi64(m2, m3); \ +} while(0) + + +#define LOAD_MSG_10_3(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m4, m5); \ +b1 = _mm_unpacklo_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_10_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpackhi_epi64(m4, m5); \ +b1 = _mm_unpackhi_epi64(m6, m7); \ +} while(0) + + +#define LOAD_MSG_11_1(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m7, m2); \ +b1 = _mm_unpackhi_epi64(m4, m6); \ +} while(0) + + +#define LOAD_MSG_11_2(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m5, m4); \ +b1 = _mm_alignr_epi8(m3, m7, 8); \ +} while(0) + + +#define LOAD_MSG_11_3(b0, b1) \ +do \ +{ \ +b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \ +b1 = _mm_unpackhi_epi64(m5, m2); \ +} while(0) + + +#define LOAD_MSG_11_4(b0, b1) \ +do \ +{ \ +b0 = _mm_unpacklo_epi64(m6, m1); \ +b1 = _mm_unpackhi_epi64(m3, m1); \ +} while(0) + + +#endif + diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b-round.h b/src/Native/libbeamhash/crypto/blake/sse/blake2b-round.h new file mode 100644 index 000000000..aeb3bb134 --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2b-round.h @@ -0,0 +1,170 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ +#pragma once +#ifndef __BLAKE2B_ROUND_H__ +#define __BLAKE2B_ROUND_H__ + +#define LOAD(p) _mm_load_si128( (const __m128i *)(p) ) +#define STORE(p,r) _mm_store_si128((__m128i *)(p), r) + +#define LOADU(p) _mm_loadu_si128( (const __m128i *)(p) ) +#define STOREU(p,r) _mm_storeu_si128((__m128i *)(p), r) + +#define TOF(reg) _mm_castsi128_ps((reg)) +#define TOI(reg) _mm_castps_si128((reg)) + +#define LIKELY(x) __builtin_expect((x),1) + + +/* Microarchitecture-specific macros */ +#ifndef HAVE_XOP +#ifdef HAVE_SSSE3 +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \ + : (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c)))) +#else +#define _mm_roti_epi64(r, c) _mm_xor_si128(_mm_srli_epi64( (r), -(c) ),_mm_slli_epi64( (r), 64-(-c) )) +#endif +#else +/* ... */ +#endif + + + +#define G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -32); \ + row4h = _mm_roti_epi64(row4h, -32); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -24); \ + row2h = _mm_roti_epi64(row2h, -24); \ + +#define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -16); \ + row4h = _mm_roti_epi64(row4h, -16); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -63); \ + row2h = _mm_roti_epi64(row2h, -63); \ + +#if defined(HAVE_SSSE3) +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2h, row2l, 8); \ + t1 = _mm_alignr_epi8(row2l, row2h, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4h, row4l, 8); \ + t1 = _mm_alignr_epi8(row4l, row4h, 8); \ + row4l = t1; \ + row4h = t0; + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = _mm_alignr_epi8(row2l, row2h, 8); \ + t1 = _mm_alignr_epi8(row2h, row2l, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4l, row4h, 8); \ + t1 = _mm_alignr_epi8(row4h, row4l, 8); \ + row4l = t1; \ + row4h = t0; +#else + +#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row4l;\ + t1 = row2l;\ + row4l = row3l;\ + row3l = row3h;\ + row3h = row4l;\ + row4l = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t0, t0)); \ + row4h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row4h, row4h)); \ + row2l = _mm_unpackhi_epi64(row2l, _mm_unpacklo_epi64(row2h, row2h)); \ + row2h = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(t1, t1)) + +#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ + t0 = row3l;\ + row3l = row3h;\ + row3h = t0;\ + t0 = row2l;\ + t1 = row4l;\ + row2l = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(row2l, row2l)); \ + row2h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row2h, row2h)); \ + row4l = _mm_unpackhi_epi64(row4l, _mm_unpacklo_epi64(row4h, row4h)); \ + row4h = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t1, t1)) + +#endif + +#if defined(HAVE_SSE41) +#include "blake2b-load-sse41.h" +#else +#include "blake2b-load-sse2.h" +#endif + +#define ROUND(r) \ + LOAD_MSG_ ##r ##_1(b0, b1); \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + LOAD_MSG_ ##r ##_2(b0, b1); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ + LOAD_MSG_ ##r ##_3(b0, b1); \ + G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + LOAD_MSG_ ##r ##_4(b0, b1); \ + G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ + UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); + +#endif + +#define BLAKE2_ROUND(row1l,row1h,row2l,row2h,row3l,row3h,row4l,row4h) \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + \ + DIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + \ + UNDIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2b.cpp b/src/Native/libbeamhash/crypto/blake/sse/blake2b.cpp new file mode 100644 index 000000000..1ff374b8f --- /dev/null +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2b.cpp @@ -0,0 +1,339 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +#include "blake2-config.h" + +#include +#if defined(HAVE_SSSE3) +#include +#endif +#if defined(HAVE_SSE41) +#include +#endif +#if defined(HAVE_AVX) +#include +#endif +#if defined(HAVE_XOP) +#include +#endif + +#include "blake2b-round.h" + +ALIGN( 64 ) static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + //blake2b_init0( S ); + const uint8_t * v = ( const uint8_t * )( blake2b_IV ); + const uint8_t * p = ( const uint8_t * )( P ); + uint8_t * h = ( uint8_t * )( S->h ); + /* IV XOR ParamBlock */ + memset( S, 0, sizeof( blake2b_state ) ); + + for( int i = 0; i < BLAKE2B_OUTBYTES; ++i ) h[i] = v[i] ^ p[i]; + + return 0; +} + +/* Some sort of default parameter block initialization, for sequential blake2b */ +int blake2b_init( blake2b_state *S, const uint8_t outlen ) +{ + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + const blake2b_param P = + { + outlen, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + {0}, + {0}, + {0} + }; + return blake2b_init_param( S, &P ); +} + +int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen ) +{ + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( ( !keylen ) || keylen > BLAKE2B_KEYBYTES ) return -1; + + const blake2b_param P = + { + outlen, + keylen, + 1, + 1, + 0, + 0, + 0, + 0, + {0}, + {0}, + {0} + }; + + if( blake2b_init_param( S, &P ) < 0 ) + return 0; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +static inline int blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + __m128i row1l, row1h; + __m128i row2l, row2h; + __m128i row3l, row3h; + __m128i row4l, row4h; + __m128i b0, b1; + __m128i t0, t1; +#if defined(HAVE_SSSE3) && !defined(HAVE_XOP) + const __m128i r16 = _mm_setr_epi8( 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9 ); + const __m128i r24 = _mm_setr_epi8( 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10 ); +#endif +#if defined(HAVE_SSE41) + const __m128i m0 = LOADU( block + 00 ); + const __m128i m1 = LOADU( block + 16 ); + const __m128i m2 = LOADU( block + 32 ); + const __m128i m3 = LOADU( block + 48 ); + const __m128i m4 = LOADU( block + 64 ); + const __m128i m5 = LOADU( block + 80 ); + const __m128i m6 = LOADU( block + 96 ); + const __m128i m7 = LOADU( block + 112 ); +#else + const uint64_t m0 = ( ( uint64_t * )block )[ 0]; + const uint64_t m1 = ( ( uint64_t * )block )[ 1]; + const uint64_t m2 = ( ( uint64_t * )block )[ 2]; + const uint64_t m3 = ( ( uint64_t * )block )[ 3]; + const uint64_t m4 = ( ( uint64_t * )block )[ 4]; + const uint64_t m5 = ( ( uint64_t * )block )[ 5]; + const uint64_t m6 = ( ( uint64_t * )block )[ 6]; + const uint64_t m7 = ( ( uint64_t * )block )[ 7]; + const uint64_t m8 = ( ( uint64_t * )block )[ 8]; + const uint64_t m9 = ( ( uint64_t * )block )[ 9]; + const uint64_t m10 = ( ( uint64_t * )block )[10]; + const uint64_t m11 = ( ( uint64_t * )block )[11]; + const uint64_t m12 = ( ( uint64_t * )block )[12]; + const uint64_t m13 = ( ( uint64_t * )block )[13]; + const uint64_t m14 = ( ( uint64_t * )block )[14]; + const uint64_t m15 = ( ( uint64_t * )block )[15]; +#endif + row1l = LOADU( &S->h[0] ); + row1h = LOADU( &S->h[2] ); + row2l = LOADU( &S->h[4] ); + row2h = LOADU( &S->h[6] ); + row3l = LOADU( &blake2b_IV[0] ); + row3h = LOADU( &blake2b_IV[2] ); + row4l = _mm_xor_si128( LOADU( &blake2b_IV[4] ), _mm_set_epi32(0,0,0,S->counter) ); + row4h = _mm_xor_si128( LOADU( &blake2b_IV[6] ), _mm_set_epi32(0,0,0L-S->lastblock,0L-S->lastblock) ); + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + row1l = _mm_xor_si128( row3l, row1l ); + row1h = _mm_xor_si128( row3h, row1h ); + STOREU( &S->h[0], _mm_xor_si128( LOADU( &S->h[0] ), row1l ) ); + STOREU( &S->h[2], _mm_xor_si128( LOADU( &S->h[2] ), row1h ) ); + row2l = _mm_xor_si128( row4l, row2l ); + row2h = _mm_xor_si128( row4h, row2h ); + STOREU( &S->h[4], _mm_xor_si128( LOADU( &S->h[4] ), row2l ) ); + STOREU( &S->h[6], _mm_xor_si128( LOADU( &S->h[6] ), row2h ) ); + return 0; +} + + +int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen ) +{ + while( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + + if( inlen > fill ) + { + memcpy( S->buf + left, in, fill ); // Fill buffer + in += fill; + inlen -= fill; + S->counter += BLAKE2B_BLOCKBYTES; + blake2b_compress( S, S->buf ); // Compress + S->buflen = 0; + } + else // inlen <= fill + { + memcpy( S->buf + left, in, inlen ); + S->buflen += (uint8_t)inlen; // not enough to compress + in += inlen; + inlen = 0; + } + } + + return 0; +} + + +int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen ) +{ + if( outlen > BLAKE2B_OUTBYTES ) + return -1; + + if( S->buflen > BLAKE2B_BLOCKBYTES ) + { + S->counter += BLAKE2B_BLOCKBYTES; + blake2b_compress( S, S->buf ); + S->buflen -= BLAKE2B_BLOCKBYTES; + memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen ); + } + + S->counter += S->buflen; + S->lastblock = 1; + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + memcpy( out, &S->h[0], outlen ); + S->lastblock = 0; + return 0; +} + + +int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen ) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if ( NULL == in ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key ) keylen = 0; + + if( keylen ) + { + if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2b_init( S, outlen ) < 0 ) return -1; + } + + blake2b_update( S, ( const uint8_t * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2b( out, in, NULL, BLAKE2B_OUTBYTES, inlen, 0 ); +} +#endif + +#if defined(BLAKE2B_SELFTEST) +#include +#include "blake2-kat.h" +int main( int argc, char **argv ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[KAT_LENGTH]; + + for( size_t i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + for( size_t i = 0; i < KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + puts( "error" ); + return -1; + } + } + + puts( "ok" ); + return 0; +} +#endif + +int blake2b_long(uint8_t *out, const void *in, const uint32_t outlen, const uint64_t inlen) +{ + blake2b_state blake_state; + if (outlen <= BLAKE2B_OUTBYTES) + { + blake2b_init(&blake_state, (uint8_t)outlen); + blake2b_update(&blake_state, (const uint8_t*)&outlen, sizeof(uint32_t)); + blake2b_update(&blake_state, (const uint8_t *)in, inlen); + blake2b_final(&blake_state, out, (uint8_t)outlen); + } + else + { + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + uint8_t in_buffer[BLAKE2B_OUTBYTES]; + blake2b_init(&blake_state, BLAKE2B_OUTBYTES); + blake2b_update(&blake_state, (const uint8_t*)&outlen, sizeof(uint32_t)); + blake2b_update(&blake_state, (const uint8_t *)in, inlen); + blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + uint32_t toproduce = outlen - BLAKE2B_OUTBYTES / 2; + while (toproduce > BLAKE2B_OUTBYTES) + { + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + blake2b(out_buffer, in_buffer, NULL, BLAKE2B_OUTBYTES, BLAKE2B_OUTBYTES, 0); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + blake2b(out_buffer, in_buffer, NULL, (uint8_t)toproduce, BLAKE2B_OUTBYTES, 0); + memcpy(out, out_buffer, toproduce); + + } + return 0; +} diff --git a/src/Native/libbeamhash/crypto/common.h b/src/Native/libbeamhash/crypto/common.h new file mode 100644 index 000000000..60bdfa538 --- /dev/null +++ b/src/Native/libbeamhash/crypto/common.h @@ -0,0 +1,69 @@ +// 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_COMMON_H +#define BITCOIN_CRYPTO_COMMON_H + +#if defined(HAVE_CONFIG_H) +#include "bitcoin-config.h" +#endif + +#include +#include + +#if defined(_MSC_VER) || defined(__APPLE__) || defined(__ANDROID__) +#include "compat/endian.h" +#endif + +uint16_t static inline ReadLE16(const unsigned char* ptr) +{ + return le16toh(*((uint16_t*)ptr)); +} + +uint32_t static inline ReadLE32(const unsigned char* ptr) +{ + return le32toh(*((uint32_t*)ptr)); +} + +uint64_t static inline ReadLE64(const unsigned char* ptr) +{ + return le64toh(*((uint64_t*)ptr)); +} + +void static inline WriteLE16(unsigned char* ptr, uint16_t x) +{ + *((uint16_t*)ptr) = htole16(x); +} + +void static inline WriteLE32(unsigned char* ptr, uint32_t x) +{ + *((uint32_t*)ptr) = htole32(x); +} + +void static inline WriteLE64(unsigned char* ptr, uint64_t x) +{ + *((uint64_t*)ptr) = htole64(x); +} + +uint32_t static inline ReadBE32(const unsigned char* ptr) +{ + return be32toh(*((uint32_t*)ptr)); +} + +uint64_t static inline ReadBE64(const unsigned char* ptr) +{ + return be64toh(*((uint64_t*)ptr)); +} + +void static inline WriteBE32(unsigned char* ptr, uint32_t x) +{ + *((uint32_t*)ptr) = htobe32(x); +} + +void static inline WriteBE64(unsigned char* ptr, uint64_t x) +{ + *((uint64_t*)ptr) = htobe64(x); +} + +#endif // BITCOIN_CRYPTO_COMMON_H diff --git a/src/Native/libbeamhash/crypto/compat/byteswap.h b/src/Native/libbeamhash/crypto/compat/byteswap.h new file mode 100644 index 000000000..9f97f9061 --- /dev/null +++ b/src/Native/libbeamhash/crypto/compat/byteswap.h @@ -0,0 +1,47 @@ +// 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/crypto/compat/endian.h new file mode 100644 index 000000000..167bce5b9 --- /dev/null +++ b/src/Native/libbeamhash/crypto/compat/endian.h @@ -0,0 +1,196 @@ +// 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_ENDIAN_H +#define BITCOIN_COMPAT_ENDIAN_H + +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include + +#include "byteswap.h" + +#if defined(HAVE_ENDIAN_H) +#include +#elif defined(HAVE_SYS_ENDIAN_H) +#include +#endif + +#if defined(WORDS_BIGENDIAN) + +#if HAVE_DECL_HTOBE16 == 0 +inline uint16_t htobe16(uint16_t host_16bits) +{ + return host_16bits; +} +#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 + +#if HAVE_DECL_BE16TOH == 0 +inline uint16_t be16toh(uint16_t big_endian_16bits) +{ + return big_endian_16bits; +} +#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 + +#if HAVE_DECL_HTOBE32 == 0 +inline uint32_t htobe32(uint32_t host_32bits) +{ + return host_32bits; +} +#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 + +#if HAVE_DECL_BE32TOH == 0 +inline uint32_t be32toh(uint32_t big_endian_32bits) +{ + return big_endian_32bits; +} +#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 + +#if HAVE_DECL_HTOBE64 == 0 +inline uint64_t htobe64(uint64_t host_64bits) +{ + return host_64bits; +} +#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 + +#if HAVE_DECL_BE64TOH == 0 +inline uint64_t be64toh(uint64_t big_endian_64bits) +{ + return big_endian_64bits; +} +#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 + +#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 + +#if HAVE_DECL_HTOLE16 == 0 +inline uint16_t htole16(uint16_t host_16bits) +{ + return host_16bits; +} +#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 + +#if HAVE_DECL_LE16TOH == 0 +inline uint16_t le16toh(uint16_t little_endian_16bits) +{ + return little_endian_16bits; +} +#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 + +#if HAVE_DECL_HTOLE32 == 0 +inline uint32_t htole32(uint32_t host_32bits) +{ + return host_32bits; +} +#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 + +#if HAVE_DECL_LE32TOH == 0 +inline uint32_t le32toh(uint32_t little_endian_32bits) +{ + return little_endian_32bits; +} +#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 + +#if HAVE_DECL_HTOLE64 == 0 +inline uint64_t htole64(uint64_t host_64bits) +{ + return host_64bits; +} +#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 + +#if HAVE_DECL_LE64TOH == 0 +inline uint64_t le64toh(uint64_t little_endian_64bits) +{ + return little_endian_64bits; +} +#endif // HAVE_DECL_LE64TOH + +#endif // WORDS_BIGENDIAN + +#endif // BITCOIN_COMPAT_ENDIAN_H \ No newline at end of file diff --git a/src/Native/libbeamhash/crypto/equihashR.cpp b/src/Native/libbeamhash/crypto/equihashR.cpp new file mode 100644 index 000000000..43f9d2e84 --- /dev/null +++ b/src/Native/libbeamhash/crypto/equihashR.cpp @@ -0,0 +1,708 @@ +// 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 new file mode 100644 index 000000000..fd0baa045 --- /dev/null +++ b/src/Native/libbeamhash/crypto/equihashR.h @@ -0,0 +1,255 @@ +// 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/powScheme.h b/src/Native/libbeamhash/crypto/powScheme.h new file mode 100644 index 000000000..8051ddc85 --- /dev/null +++ b/src/Native/libbeamhash/crypto/powScheme.h @@ -0,0 +1,49 @@ +#include + +#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 + +enum SolverCancelCheck +{ + ListGeneration, + ListSorting, + ListColliding, + RoundEnd, + FinalSorting, + FinalColliding, + PartialGeneration, + PartialSorting, + PartialSubtreeEnd, + PartialIndexEnd, + PartialEnd, + MixElements +}; + +class SolverCancelledException : public std::exception +{ + virtual const char* what() const throw() { + return "BeamHash solver was cancelled"; + } +}; + + +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 OptimisedSolve(const blake2b_state& base_state, + const std::function&)> validBlock, + const std::function cancelled) = 0; +#endif + +}; + +#endif diff --git a/src/Native/libbeamhash/crypto/sha256.h b/src/Native/libbeamhash/crypto/sha256.h new file mode 100644 index 000000000..b9d0f6483 --- /dev/null +++ b/src/Native/libbeamhash/crypto/sha256.h @@ -0,0 +1,23 @@ +/* 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/dllmain.cpp b/src/Native/libbeamhash/dllmain.cpp new file mode 100644 index 000000000..69b58914b --- /dev/null +++ b/src/Native/libbeamhash/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/src/Native/libbeamhash/exports.cpp b/src/Native/libbeamhash/exports.cpp new file mode 100644 index 000000000..ca1a49bb1 --- /dev/null +++ b/src/Native/libbeamhash/exports.cpp @@ -0,0 +1,39 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "beamhashverify.h" + +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif + +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) { + return false; + } + + 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/libbeamhash.sln b/src/Native/libbeamhash/libbeamhash.sln new file mode 100644 index 000000000..8c6cddc1f --- /dev/null +++ b/src/Native/libbeamhash/libbeamhash.sln @@ -0,0 +1,31 @@ + +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}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libbeamhash/libbeamhash.vcxproj b/src/Native/libbeamhash/libbeamhash.vcxproj new file mode 100644 index 000000000..4bc841d52 --- /dev/null +++ b/src/Native/libbeamhash/libbeamhash.vcxproj @@ -0,0 +1,229 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libbeamhash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libmultihash\windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libbeamhash/random.cpp b/src/Native/libbeamhash/random.cpp new file mode 100644 index 000000000..9fc6215ec --- /dev/null +++ b/src/Native/libbeamhash/random.cpp @@ -0,0 +1,89 @@ +// 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 new file mode 100644 index 000000000..8cec678ef --- /dev/null +++ b/src/Native/libbeamhash/random.h @@ -0,0 +1,74 @@ +// 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 new file mode 100644 index 000000000..1402035f1 --- /dev/null +++ b/src/Native/libbeamhash/serialize.h @@ -0,0 +1,997 @@ +// 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/stdafx.cpp b/src/Native/libbeamhash/stdafx.cpp new file mode 100644 index 000000000..bd27597c6 --- /dev/null +++ b/src/Native/libbeamhash/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// $safeprojectname$.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/src/Native/libbeamhash/stdafx.h b/src/Native/libbeamhash/stdafx.h new file mode 100644 index 000000000..f3a07375c --- /dev/null +++ b/src/Native/libbeamhash/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + + + +// TODO: reference additional headers your program requires here diff --git a/src/Native/libbeamhash/stdint.h b/src/Native/libbeamhash/stdint.h new file mode 100644 index 000000000..4fe0ef9a9 --- /dev/null +++ b/src/Native/libbeamhash/stdint.h @@ -0,0 +1,259 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/src/Native/libbeamhash/support/cleanse.cpp b/src/Native/libbeamhash/support/cleanse.cpp new file mode 100644 index 000000000..a2141b244 --- /dev/null +++ b/src/Native/libbeamhash/support/cleanse.cpp @@ -0,0 +1,13 @@ +// 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 new file mode 100644 index 000000000..3e02aa8fd --- /dev/null +++ b/src/Native/libbeamhash/support/cleanse.h @@ -0,0 +1,13 @@ +// 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/targetver.h b/src/Native/libbeamhash/targetver.h new file mode 100644 index 000000000..87c0086de --- /dev/null +++ b/src/Native/libbeamhash/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/src/Native/libbeamhash/tinyformat.h b/src/Native/libbeamhash/tinyformat.h new file mode 100644 index 000000000..57f767250 --- /dev/null +++ b/src/Native/libbeamhash/tinyformat.h @@ -0,0 +1,1049 @@ +// 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 new file mode 100644 index 000000000..25148808c --- /dev/null +++ b/src/Native/libbeamhash/uint256.cpp @@ -0,0 +1,146 @@ +// 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 new file mode 100644 index 000000000..3729c981a --- /dev/null +++ b/src/Native/libbeamhash/uint256.h @@ -0,0 +1,158 @@ +// 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 new file mode 100644 index 000000000..e59783e99 --- /dev/null +++ b/src/Native/libbeamhash/util.cpp @@ -0,0 +1,79 @@ +// 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 new file mode 100644 index 000000000..6a2f92f1e --- /dev/null +++ b/src/Native/libbeamhash/util.h @@ -0,0 +1,58 @@ +// 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 new file mode 100644 index 000000000..0a5fbb3d2 --- /dev/null +++ b/src/Native/libbeamhash/utilstrencodings.cpp @@ -0,0 +1,692 @@ +// 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 new file mode 100644 index 000000000..ccdc6a76b --- /dev/null +++ b/src/Native/libbeamhash/utilstrencodings.h @@ -0,0 +1,122 @@ +// 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/libmultihash/Makefile b/src/Native/libmultihash/Makefile index d7f0618c9..9b4099bf0 100644 --- a/src/Native/libmultihash/Makefile +++ b/src/Native/libmultihash/Makefile @@ -21,7 +21,8 @@ OBJECTS = bcrypt.o blake.o c11.o dcrypt.o fresh.o lane.o \ equi/uint256.o equi/arith_uint256.o equi/crypto/hmac_sha512.o \ equi/crypto/sha1.o equi/crypto/sha512.o equi/crypto/sha256.o \ equi/crypto/hmac_sha256.o equi/crypto/equihash.o equi/crypto/ripemd160.o \ - equi/equihashverify.o sha512_256.o sha256dt.o + equi/equihashverify.o sha512_256.o sha256dt.o \ + minotaur/crypto/sha256.o minotaur/crypto/yespower.o minotaur/minotaurx.o all: $(TARGET) diff --git a/src/Native/libmultihash/exports.cpp b/src/Native/libmultihash/exports.cpp index 715aaa763..56ff95cea 100644 --- a/src/Native/libmultihash/exports.cpp +++ b/src/Native/libmultihash/exports.cpp @@ -56,6 +56,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "verthash/h2.h" #include "equi/equihashverify.h" #include "heavyhash/heavyhash.h" +#include "minotaur/minotaurx.h" #ifdef _WIN32 #include "blake2/ref/blake2.h" @@ -333,3 +334,8 @@ extern "C" MODULE_API bool equihash_verify_96_5_export(const char* header, int h return verifyEH_96_5(header, vecSolution, personalization); } + +extern "C" MODULE_API void minotaurx_export(const char* input, char* output) +{ + minotaurx_hash(input, output); +} \ No newline at end of file diff --git a/src/Native/libmultihash/libmultihash.vcxproj b/src/Native/libmultihash/libmultihash.vcxproj index c7f34bc94..056fc83b1 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj +++ b/src/Native/libmultihash/libmultihash.vcxproj @@ -1,370 +1,378 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {2DE74E14-BF6D-4046-951B-8EBC8A1BA009} - Win32Proj - netmultihashnative - 10.0 - libmultihash - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MaxSpeed - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009} + Win32Proj + netmultihashnative + 10.0 + libmultihash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MaxSpeed + + + + + + + + + + + + + + diff --git a/src/Native/libmultihash/libmultihash.vcxproj.filters b/src/Native/libmultihash/libmultihash.vcxproj.filters index 0ee5ca16d..55d1c6f3e 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj.filters +++ b/src/Native/libmultihash/libmultihash.vcxproj.filters @@ -1,588 +1,612 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + diff --git a/src/Native/libmultihash/minotaur/crypto/insecure_memzero.h b/src/Native/libmultihash/minotaur/crypto/insecure_memzero.h new file mode 100644 index 000000000..2fd97d866 --- /dev/null +++ b/src/Native/libmultihash/minotaur/crypto/insecure_memzero.h @@ -0,0 +1 @@ +#define insecure_memzero(buf, len) /* empty */ \ No newline at end of file diff --git a/src/Native/libmultihash/minotaur/crypto/sha256.c b/src/Native/libmultihash/minotaur/crypto/sha256.c new file mode 100644 index 000000000..4981547de --- /dev/null +++ b/src/Native/libmultihash/minotaur/crypto/sha256.c @@ -0,0 +1,641 @@ +/*- + * Copyright 2005-2016 Colin Percival + * Copyright 2016-2018,2021 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "insecure_memzero.h" +#include "sysendian.h" + +#include "sha256.h" + +/* + * Encode a length len*2 vector of (uint32_t) into a length len*8 vector of + * (uint8_t) in big-endian form. + */ +static void +be32enc_vect(uint8_t * dst, const uint32_t * src, size_t len) +{ + + /* Encode vector, two words at a time. */ + do { + be32enc(&dst[0], src[0]); + be32enc(&dst[4], src[1]); + src += 2; + dst += 8; + } while (--len); +} + +/* + * Decode a big-endian length len*8 vector of (uint8_t) into a length + * len*2 vector of (uint32_t). + */ +static void +be32dec_vect(uint32_t * dst, const uint8_t * src, size_t len) +{ + + /* Decode vector, two words at a time. */ + do { + dst[0] = be32dec(&src[0]); + dst[1] = be32dec(&src[4]); + src += 8; + dst += 2; + } while (--len); +} + +/* SHA256 round constants. */ +static const uint32_t Krnd[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#if 1 /* Explicit caching/reuse of common subexpression between rounds */ +#define Maj(x, y, z) (y ^ ((x_xor_y = x ^ y) & y_xor_z)) +#else /* Let the compiler cache/reuse or not */ +#define Maj(x, y, z) (y ^ ((x ^ y) & (y ^ z))) +#endif +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + h += S1(e) + Ch(e, f, g) + k; \ + d += h; \ + h += S0(a) + Maj(a, b, c); \ + y_xor_z = x_xor_y; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, ii) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i + ii] + Krnd[i + ii]) + +/* Message schedule computation */ +#define MSCH(W, ii, i) \ + W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii] + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t state[8], + const uint8_t block[64], + uint32_t W[64], uint32_t S[8]) +{ + int i; + + /* 1. Prepare the first part of the message schedule W. */ + be32dec_vect(W, block, 8); + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + for (i = 0; i < 64; i += 16) { + uint32_t x_xor_y, y_xor_z = S[(65 - i) % 8] ^ S[(66 - i) % 8]; + RNDr(S, W, 0, i); + RNDr(S, W, 1, i); + RNDr(S, W, 2, i); + RNDr(S, W, 3, i); + RNDr(S, W, 4, i); + RNDr(S, W, 5, i); + RNDr(S, W, 6, i); + RNDr(S, W, 7, i); + RNDr(S, W, 8, i); + RNDr(S, W, 9, i); + RNDr(S, W, 10, i); + RNDr(S, W, 11, i); + RNDr(S, W, 12, i); + RNDr(S, W, 13, i); + RNDr(S, W, 14, i); + RNDr(S, W, 15, i); + + if (i == 48) + break; + MSCH(W, 0, i); + MSCH(W, 1, i); + MSCH(W, 2, i); + MSCH(W, 3, i); + MSCH(W, 4, i); + MSCH(W, 5, i); + MSCH(W, 6, i); + MSCH(W, 7, i); + MSCH(W, 8, i); + MSCH(W, 9, i); + MSCH(W, 10, i); + MSCH(W, 11, i); + MSCH(W, 12, i); + MSCH(W, 13, i); + MSCH(W, 14, i); + MSCH(W, 15, i); + } + + /* 4. Mix local working variables into global state. */ + state[0] += S[0]; + state[1] += S[1]; + state[2] += S[2]; + state[3] += S[3]; + state[4] += S[4]; + state[5] += S[5]; + state[6] += S[6]; + state[7] += S[7]; +} + +static const uint8_t PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[72]) +{ + size_t r; + + /* Figure out how many bytes we have buffered. */ + r = (ctx->count >> 3) & 0x3f; + + /* Pad to 56 mod 64, transforming if we finish a block en route. */ + if (r < 56) { + /* Pad to 56 mod 64. */ + memcpy(&ctx->buf[r], PAD, 56 - r); + } else { + /* Finish the current block and mix. */ + memcpy(&ctx->buf[r], PAD, 64 - r); + SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); + + /* The start of the final block is all zeroes. */ + memset(&ctx->buf[0], 0, 56); + } + + /* Add the terminating bit-count. */ + be64enc(&ctx->buf[56], ctx->count); + + /* Mix in the final block. */ + SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); +} + +/* Magic initialization constants. */ +static const uint32_t initial_state[8] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +/** + * SHA256_Init(ctx): + * Initialize the SHA256 context ${ctx}. + */ +void +SHA256_Init(SHA256_CTX * ctx) +{ + + /* Zero bits processed so far. */ + ctx->count = 0; + + /* Initialize state. */ + memcpy(ctx->state, initial_state, sizeof(initial_state)); +} + +/** + * SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. + */ +static void +_SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len, + uint32_t tmp32[72]) +{ + uint32_t r; + const uint8_t * src = in; + + /* Return immediately if we have nothing to do. */ + if (len == 0) + return; + + /* Number of bytes left in the buffer from previous updates. */ + r = (ctx->count >> 3) & 0x3f; + + /* Update number of bits. */ + ctx->count += (uint64_t)(len) << 3; + + /* Handle the case where we don't need to perform any transforms. */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block. */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks. */ + while (len >= 64) { + SHA256_Transform(ctx->state, src, &tmp32[0], &tmp32[64]); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer. */ + memcpy(ctx->buf, src, len); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len) +{ + uint32_t tmp32[72]; + + /* Call the real function. */ + _SHA256_Update(ctx, in, len, tmp32); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); +} + +/** + * SHA256_Final(digest, ctx): + * Output the SHA256 hash of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +static void +_SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx, + uint32_t tmp32[72]) +{ + + /* Add padding. */ + SHA256_Pad(ctx, tmp32); + + /* Write the hash. */ + be32enc_vect(digest, ctx->state, 4); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx) +{ + uint32_t tmp32[72]; + + /* Call the real function. */ + _SHA256_Final(digest, ctx, tmp32); + + /* Clear the context state. */ + insecure_memzero(ctx, sizeof(SHA256_CTX)); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); +} + +/** + * SHA256_Buf(in, len, digest): + * Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}. + */ +void +SHA256_Buf(const void * in, size_t len, uint8_t digest[32]) +{ + SHA256_CTX ctx; + uint32_t tmp32[72]; + + SHA256_Init(&ctx); + _SHA256_Update(&ctx, in, len, tmp32); + _SHA256_Final(digest, &ctx, tmp32); + + /* Clean the stack. */ + insecure_memzero(&ctx, sizeof(SHA256_CTX)); + insecure_memzero(tmp32, 288); +} + +/** + * HMAC_SHA256_Init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +static void +_HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen, + uint32_t tmp32[72], uint8_t pad[64], + uint8_t khash[32]) +{ + const uint8_t * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + _SHA256_Update(&ctx->ictx, K, Klen, tmp32); + _SHA256_Final(khash, &ctx->ictx, tmp32); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + _SHA256_Update(&ctx->ictx, pad, 64, tmp32); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + _SHA256_Update(&ctx->octx, pad, 64, tmp32); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + uint32_t tmp32[72]; + uint8_t pad[64]; + uint8_t khash[32]; + + /* Call the real function. */ + _HMAC_SHA256_Init(ctx, _K, Klen, tmp32, pad, khash); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); + insecure_memzero(khash, 32); + insecure_memzero(pad, 64); +} + +/** + * HMAC_SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +static void +_HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len, + uint32_t tmp32[72]) +{ + + /* Feed data to the inner SHA256 operation. */ + _SHA256_Update(&ctx->ictx, in, len, tmp32); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len) +{ + uint32_t tmp32[72]; + + /* Call the real function. */ + _HMAC_SHA256_Update(ctx, in, len, tmp32); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); +} + +/** + * HMAC_SHA256_Final(digest, ctx): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +static void +_HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx, + uint32_t tmp32[72], uint8_t ihash[32]) +{ + + /* Finish the inner SHA256 operation. */ + _SHA256_Final(ihash, &ctx->ictx, tmp32); + + /* Feed the inner hash to the outer SHA256 operation. */ + _SHA256_Update(&ctx->octx, ihash, 32, tmp32); + + /* Finish the outer SHA256 operation. */ + _SHA256_Final(digest, &ctx->octx, tmp32); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx) +{ + uint32_t tmp32[72]; + uint8_t ihash[32]; + + /* Call the real function. */ + _HMAC_SHA256_Final(digest, ctx, tmp32, ihash); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); + insecure_memzero(ihash, 32); +} + +/** + * HMAC_SHA256_Buf(K, Klen, in, len, digest): + * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of + * length ${Klen}, and write the result to ${digest}. + */ +void +HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len, + uint8_t digest[32]) +{ + HMAC_SHA256_CTX ctx; + uint32_t tmp32[72]; + uint8_t tmp8[96]; + + _HMAC_SHA256_Init(&ctx, K, Klen, tmp32, &tmp8[0], &tmp8[64]); + _HMAC_SHA256_Update(&ctx, in, len, tmp32); + _HMAC_SHA256_Final(digest, &ctx, tmp32, &tmp8[0]); + + /* Clean the stack. */ + insecure_memzero(&ctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(tmp32, 288); + insecure_memzero(tmp8, 96); +} + +/* Add padding and terminating bit-count, but don't invoke Transform yet. */ +static int +SHA256_Pad_Almost(SHA256_CTX * ctx, uint8_t len[8], + uint32_t tmp32[72]) +{ + uint32_t r; + + r = (ctx->count >> 3) & 0x3f; + if (r >= 56) + return -1; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be64enc(len, ctx->count); + + /* Add 1--56 bytes so that the resulting length is 56 mod 64. */ + _SHA256_Update(ctx, PAD, 56 - r, tmp32); + + /* Add the terminating bit-count. */ + ctx->buf[63] = len[7]; + _SHA256_Update(ctx, len, 7, tmp32); + + return 0; +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX Phctx, PShctx, hctx; + uint32_t tmp32[72]; + union { + uint8_t tmp8[96]; + uint32_t state[8]; + } u; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Sanity-check. */ + assert(dkLen <= 32 * (size_t)(UINT32_MAX)); + + if (c == 1 && (dkLen & 31) == 0 && (saltlen & 63) <= 51) { + uint32_t oldcount; + uint8_t * ivecp; + + /* Compute HMAC state after processing P and S. */ + _HMAC_SHA256_Init(&hctx, passwd, passwdlen, + tmp32, &u.tmp8[0], &u.tmp8[64]); + _HMAC_SHA256_Update(&hctx, salt, saltlen, tmp32); + + /* Prepare ictx padding. */ + oldcount = hctx.ictx.count & (0x3f << 3); + _HMAC_SHA256_Update(&hctx, "\0\0\0", 4, tmp32); + if ((hctx.ictx.count & (0x3f << 3)) < oldcount || + SHA256_Pad_Almost(&hctx.ictx, u.tmp8, tmp32)) + goto generic; /* Can't happen due to saltlen check */ + ivecp = hctx.ictx.buf + (oldcount >> 3); + + /* Prepare octx padding. */ + hctx.octx.count += 32 << 3; + SHA256_Pad_Almost(&hctx.octx, u.tmp8, tmp32); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivecp, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(u.state, hctx.ictx.state, sizeof(u.state)); + SHA256_Transform(u.state, hctx.ictx.buf, + &tmp32[0], &tmp32[64]); + be32enc_vect(hctx.octx.buf, u.state, 4); + memcpy(u.state, hctx.octx.state, sizeof(u.state)); + SHA256_Transform(u.state, hctx.octx.buf, + &tmp32[0], &tmp32[64]); + be32enc_vect(&buf[i * 32], u.state, 4); + } + + goto cleanup; + } + +generic: + /* Compute HMAC state after processing P. */ + _HMAC_SHA256_Init(&Phctx, passwd, passwdlen, + tmp32, &u.tmp8[0], &u.tmp8[64]); + + /* Compute HMAC state after processing P and S. */ + memcpy(&PShctx, &Phctx, sizeof(HMAC_SHA256_CTX)); + _HMAC_SHA256_Update(&PShctx, salt, saltlen, tmp32); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + _HMAC_SHA256_Update(&hctx, ivec, 4, tmp32); + _HMAC_SHA256_Final(T, &hctx, tmp32, u.tmp8); + + if (c > 1) { + /* T_i = U_1 ... */ + memcpy(U, T, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + memcpy(&hctx, &Phctx, sizeof(HMAC_SHA256_CTX)); + _HMAC_SHA256_Update(&hctx, U, 32, tmp32); + _HMAC_SHA256_Final(U, &hctx, tmp32, u.tmp8); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean the stack. */ + insecure_memzero(&Phctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(U, 32); + insecure_memzero(T, 32); + +cleanup: + insecure_memzero(&hctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(tmp32, 288); + insecure_memzero(&u, sizeof(u)); +} \ No newline at end of file diff --git a/src/Native/libmultihash/minotaur/crypto/sha256.h b/src/Native/libmultihash/minotaur/crypto/sha256.h new file mode 100644 index 000000000..4b9099123 --- /dev/null +++ b/src/Native/libmultihash/minotaur/crypto/sha256.h @@ -0,0 +1,129 @@ +/*- + * Copyright 2005-2016 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Use #defines in order to avoid namespace collisions with anyone else's + * SHA256 code (e.g., the code in OpenSSL). + */ +#define SHA256_Init libcperciva_SHA256_Init +#define SHA256_Update libcperciva_SHA256_Update +#define SHA256_Final libcperciva_SHA256_Final +#define SHA256_Buf libcperciva_SHA256_Buf +#define SHA256_CTX libcperciva_SHA256_CTX +#define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init +#define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update +#define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final +#define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf +#define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX + +/* Context structure for SHA256 operations. */ +typedef struct { + uint32_t state[8]; + uint64_t count; + uint8_t buf[64]; +} SHA256_CTX; + +/** + * SHA256_Init(ctx): + * Initialize the SHA256 context ${ctx}. + */ +void SHA256_Init(SHA256_CTX *); + +/** + * SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. + */ +void SHA256_Update(SHA256_CTX *, const void *, size_t); + +/** + * SHA256_Final(digest, ctx): + * Output the SHA256 hash of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void SHA256_Final(uint8_t[32], SHA256_CTX *); + +/** + * SHA256_Buf(in, len, digest): + * Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}. + */ +void SHA256_Buf(const void *, size_t, uint8_t[32]); + +/* Context structure for HMAC-SHA256 operations. */ +typedef struct { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +/** + * HMAC_SHA256_Init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); + +/** + * HMAC_SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); + +/** + * HMAC_SHA256_Final(digest, ctx): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *); + +/** + * HMAC_SHA256_Buf(K, Klen, in, len, digest): + * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of + * length ${Klen}, and write the result to ${digest}. + */ +void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* !_SHA256_H_ */ \ No newline at end of file diff --git a/src/Native/libmultihash/minotaur/crypto/sysendian.h b/src/Native/libmultihash/minotaur/crypto/sysendian.h new file mode 100644 index 000000000..bf2215a39 --- /dev/null +++ b/src/Native/libmultihash/minotaur/crypto/sysendian.h @@ -0,0 +1,94 @@ +/*- + * Copyright 2007-2014 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +#include + +/* Avoid namespace collisions with BSD . */ +#define be32dec libcperciva_be32dec +#define be32enc libcperciva_be32enc +#define be64enc libcperciva_be64enc +#define le32dec libcperciva_le32dec +#define le32enc libcperciva_le32enc + +static inline uint32_t +be32dec(const void * pp) +{ + const uint8_t * p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void * pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline void +be64enc(void * pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static inline uint32_t +le32dec(const void * pp) +{ + const uint8_t * p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void * pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +#endif /* !_SYSENDIAN_H_ */ \ No newline at end of file diff --git a/src/Native/libmultihash/minotaur/crypto/yespower.c b/src/Native/libmultihash/minotaur/crypto/yespower.c new file mode 100644 index 000000000..e2ca167c7 --- /dev/null +++ b/src/Native/libmultihash/minotaur/crypto/yespower.c @@ -0,0 +1,1255 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2012-2019 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + * + * This is a proof-of-work focused fork of yescrypt, including optimized and + * cut-down implementation of the obsolete yescrypt 0.5 (based off its first + * submission to PHC back in 2014) and a new proof-of-work specific variation + * known as yespower 1.0. The former is intended as an upgrade for + * cryptocurrencies that already use yescrypt 0.5 and the latter may be used + * as a further upgrade (hard fork) by those and other cryptocurrencies. The + * version of algorithm to use is requested through parameters, allowing for + * both algorithms to co-exist in client and miner implementations (such as in + * preparation for a hard-fork). + */ + +#ifndef _YESPOWER_OPT_C_PASS_ +#define _YESPOWER_OPT_C_PASS_ 1 +#endif + +#if _YESPOWER_OPT_C_PASS_ == 1 +/* + * AVX and especially XOP speed up Salsa20 a lot, but needlessly result in + * extra instruction prefixes for pwxform (which we make more use of). While + * no slowdown from the prefixes is generally observed on AMD CPUs supporting + * XOP, some slowdown is sometimes observed on Intel CPUs with AVX. + */ +#ifdef __XOP__ +#elif defined(__AVX__) +#elif defined(__SSE2__) +#elif defined(__x86_64__) || defined(__i386__) +#else +#endif + +/* + * The SSE4 code version has fewer instructions than the generic SSE2 version, + * but all of the instructions are SIMD, thereby wasting the scalar execution + * units. Thus, the generic SSE2 version below actually runs faster on some + * CPUs due to its balanced mix of SIMD and scalar instructions. + */ +#undef USE_SSE4_FOR_32BIT + +#ifdef __SSE2__ +/* + * GCC before 4.9 would by default unnecessarily use store/load (without + * SSE4.1) or (V)PEXTR (with SSE4.1 or AVX) instead of simply (V)MOV. + * This was tracked as GCC bug 54349. + * "-mtune=corei7" works around this, but is only supported for GCC 4.6+. + * We use inline asm for pre-4.6 GCC, further down this file. + */ +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && __GNUC_MINOR__ < 9 && \ + !defined(__clang__) && !defined(__ICC) +#pragma GCC target ("tune=corei7") +#endif +#include +#ifdef __XOP__ +#include +#endif +#elif defined(__SSE__) +#include +#endif + +#include +#include +#include +#include + +#include "insecure_memzero.h" +#include "sha256.h" +#include "sysendian.h" + +#include "yespower.h" + +#ifdef __unix__ +#include +#endif + +#define HUGEPAGE_THRESHOLD (12 * 1024 * 1024) + +#ifdef __x86_64__ +#define HUGEPAGE_SIZE (2 * 1024 * 1024) +#else +#undef HUGEPAGE_SIZE +#endif + +static void *alloc_region(yespower_region_t *region, size_t size) +{ + size_t base_size = size; + uint8_t *base, *aligned; +#ifdef MAP_ANON + int flags = +#ifdef MAP_NOCORE + MAP_NOCORE | +#endif + MAP_ANON | MAP_PRIVATE; +#if defined(MAP_HUGETLB) && defined(HUGEPAGE_SIZE) + size_t new_size = size; + const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1; + if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) { + flags |= MAP_HUGETLB; +/* + * Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of + * huge page size, so let's round up to huge page size here. + */ + new_size = size + hugepage_mask; + new_size &= ~hugepage_mask; + } + base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, flags, -1, 0); + if (base != MAP_FAILED) { + base_size = new_size; + } else if (flags & MAP_HUGETLB) { + flags &= ~MAP_HUGETLB; + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + } + +#else + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); +#endif + if (base == MAP_FAILED) + base = NULL; + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **)&base, 64, size)) != 0) + base = NULL; + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) { + errno = ENOMEM; + } else if ((base = malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t)aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->base_size = base ? base_size : 0; + region->aligned_size = base ? size : 0; + return aligned; +} + +static inline void init_region(yespower_region_t *region) +{ + region->base = region->aligned = NULL; + region->base_size = region->aligned_size = 0; +} + +static int free_region(yespower_region_t *region) +{ + if (region->base) { +#ifdef MAP_ANON + if (munmap(region->base, region->base_size)) + return -1; +#else + free(region->base); +#endif + } + init_region(region); + return 0; +} + +#if __STDC_VERSION__ >= 199901L +/* Have restrict */ +#elif defined(__GNUC__) +#define restrict __restrict +#elif defined(_MSC_VER) +#define restrict __restrict +#else +#define restrict +#endif + +#ifdef __GNUC__ +#define unlikely(exp) __builtin_expect(exp, 0) +#else +#define unlikely(exp) (exp) +#endif + +#ifdef __SSE__ +#define PREFETCH(x, hint) _mm_prefetch((const char *)(x), (hint)); +#else +#undef PREFETCH +#endif + +typedef union { + uint32_t w[16]; + uint64_t d[8]; +#ifdef __SSE2__ + __m128i q[4]; +#endif +} salsa20_blk_t; + +static inline void salsa20_simd_shuffle(const salsa20_blk_t *Bin, + salsa20_blk_t *Bout) +{ +#define COMBINE(out, in1, in2) \ + Bout->d[out] = Bin->w[in1 * 2] | ((uint64_t)Bin->w[in2 * 2 + 1] << 32); + COMBINE(0, 0, 2) + COMBINE(1, 5, 7) + COMBINE(2, 2, 4) + COMBINE(3, 7, 1) + COMBINE(4, 4, 6) + COMBINE(5, 1, 3) + COMBINE(6, 6, 0) + COMBINE(7, 3, 5) +#undef COMBINE +} + +static inline void salsa20_simd_unshuffle(const salsa20_blk_t *Bin, + salsa20_blk_t *Bout) +{ +#define UNCOMBINE(out, in1, in2) \ + Bout->w[out * 2] = Bin->d[in1]; \ + Bout->w[out * 2 + 1] = Bin->d[in2] >> 32; + UNCOMBINE(0, 0, 6) + UNCOMBINE(1, 5, 3) + UNCOMBINE(2, 2, 0) + UNCOMBINE(3, 7, 5) + UNCOMBINE(4, 4, 2) + UNCOMBINE(5, 1, 7) + UNCOMBINE(6, 6, 4) + UNCOMBINE(7, 3, 1) +#undef UNCOMBINE +} + +#ifdef __SSE2__ +#define DECL_X \ + __m128i X0, X1, X2, X3; +#define DECL_Y \ + __m128i Y0, Y1, Y2, Y3; +#define READ_X(in) \ + X0 = (in).q[0]; X1 = (in).q[1]; X2 = (in).q[2]; X3 = (in).q[3]; +#define WRITE_X(out) \ + (out).q[0] = X0; (out).q[1] = X1; (out).q[2] = X2; (out).q[3] = X3; + +#ifdef __XOP__ +#define ARX(out, in1, in2, s) \ + out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); +#else +#define ARX(out, in1, in2, s) { \ + __m128i tmp = _mm_add_epi32(in1, in2); \ + out = _mm_xor_si128(out, _mm_slli_epi32(tmp, s)); \ + out = _mm_xor_si128(out, _mm_srli_epi32(tmp, 32 - s)); \ +} +#endif + +#define SALSA20_2ROUNDS \ + /* Operate on "columns" */ \ + ARX(X1, X0, X3, 7) \ + ARX(X2, X1, X0, 9) \ + ARX(X3, X2, X1, 13) \ + ARX(X0, X3, X2, 18) \ + /* Rearrange data */ \ + X1 = _mm_shuffle_epi32(X1, 0x93); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x39); \ + /* Operate on "rows" */ \ + ARX(X3, X0, X1, 7) \ + ARX(X2, X3, X0, 9) \ + ARX(X1, X2, X3, 13) \ + ARX(X0, X1, X2, 18) \ + /* Rearrange data */ \ + X1 = _mm_shuffle_epi32(X1, 0x39); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x93); + +/** + * Apply the Salsa20 core to the block provided in (X0 ... X3). + */ +#define SALSA20_wrapper(out, rounds) { \ + __m128i Z0 = X0, Z1 = X1, Z2 = X2, Z3 = X3; \ + rounds \ + (out).q[0] = X0 = _mm_add_epi32(X0, Z0); \ + (out).q[1] = X1 = _mm_add_epi32(X1, Z1); \ + (out).q[2] = X2 = _mm_add_epi32(X2, Z2); \ + (out).q[3] = X3 = _mm_add_epi32(X3, Z3); \ +} + +/** + * Apply the Salsa20/2 core to the block provided in X. + */ +#define SALSA20_2(out) \ + SALSA20_wrapper(out, SALSA20_2ROUNDS) + +#define SALSA20_8ROUNDS \ + SALSA20_2ROUNDS SALSA20_2ROUNDS SALSA20_2ROUNDS SALSA20_2ROUNDS + +/** + * Apply the Salsa20/8 core to the block provided in X. + */ +#define SALSA20_8(out) \ + SALSA20_wrapper(out, SALSA20_8ROUNDS) + +#define XOR_X(in) \ + X0 = _mm_xor_si128(X0, (in).q[0]); \ + X1 = _mm_xor_si128(X1, (in).q[1]); \ + X2 = _mm_xor_si128(X2, (in).q[2]); \ + X3 = _mm_xor_si128(X3, (in).q[3]); + +#define XOR_X_2(in1, in2) \ + X0 = _mm_xor_si128((in1).q[0], (in2).q[0]); \ + X1 = _mm_xor_si128((in1).q[1], (in2).q[1]); \ + X2 = _mm_xor_si128((in1).q[2], (in2).q[2]); \ + X3 = _mm_xor_si128((in1).q[3], (in2).q[3]); + +#define XOR_X_WRITE_XOR_Y_2(out, in) \ + (out).q[0] = Y0 = _mm_xor_si128((out).q[0], (in).q[0]); \ + (out).q[1] = Y1 = _mm_xor_si128((out).q[1], (in).q[1]); \ + (out).q[2] = Y2 = _mm_xor_si128((out).q[2], (in).q[2]); \ + (out).q[3] = Y3 = _mm_xor_si128((out).q[3], (in).q[3]); \ + X0 = _mm_xor_si128(X0, Y0); \ + X1 = _mm_xor_si128(X1, Y1); \ + X2 = _mm_xor_si128(X2, Y2); \ + X3 = _mm_xor_si128(X3, Y3); + +#define INTEGERIFY _mm_cvtsi128_si32(X0) + +#else /* !defined(__SSE2__) */ + +#define DECL_X \ + salsa20_blk_t X; +#define DECL_Y \ + salsa20_blk_t Y; + +#define COPY(out, in) \ + (out).d[0] = (in).d[0]; \ + (out).d[1] = (in).d[1]; \ + (out).d[2] = (in).d[2]; \ + (out).d[3] = (in).d[3]; \ + (out).d[4] = (in).d[4]; \ + (out).d[5] = (in).d[5]; \ + (out).d[6] = (in).d[6]; \ + (out).d[7] = (in).d[7]; + +#define READ_X(in) COPY(X, in) +#define WRITE_X(out) COPY(out, X) + +/** + * salsa20(B): + * Apply the Salsa20 core to the provided block. + */ +static inline void salsa20(salsa20_blk_t *restrict B, + salsa20_blk_t *restrict Bout, uint32_t doublerounds) +{ + salsa20_blk_t X; +#define x X.w + + salsa20_simd_unshuffle(B, &X); + + do { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } while (--doublerounds); +#undef x + + { + uint32_t i; + salsa20_simd_shuffle(&X, Bout); + for (i = 0; i < 16; i += 4) { + B->w[i] = Bout->w[i] += B->w[i]; + B->w[i + 1] = Bout->w[i + 1] += B->w[i + 1]; + B->w[i + 2] = Bout->w[i + 2] += B->w[i + 2]; + B->w[i + 3] = Bout->w[i + 3] += B->w[i + 3]; + } + } +} + +/** + * Apply the Salsa20/2 core to the block provided in X. + */ +#define SALSA20_2(out) \ + salsa20(&X, &out, 1); + +/** + * Apply the Salsa20/8 core to the block provided in X. + */ +#define SALSA20_8(out) \ + salsa20(&X, &out, 4); + +#define XOR(out, in1, in2) \ + (out).d[0] = (in1).d[0] ^ (in2).d[0]; \ + (out).d[1] = (in1).d[1] ^ (in2).d[1]; \ + (out).d[2] = (in1).d[2] ^ (in2).d[2]; \ + (out).d[3] = (in1).d[3] ^ (in2).d[3]; \ + (out).d[4] = (in1).d[4] ^ (in2).d[4]; \ + (out).d[5] = (in1).d[5] ^ (in2).d[5]; \ + (out).d[6] = (in1).d[6] ^ (in2).d[6]; \ + (out).d[7] = (in1).d[7] ^ (in2).d[7]; + +#define XOR_X(in) XOR(X, X, in) +#define XOR_X_2(in1, in2) XOR(X, in1, in2) +#define XOR_X_WRITE_XOR_Y_2(out, in) \ + XOR(Y, out, in) \ + COPY(out, Y) \ + XOR(X, X, Y) + +#define INTEGERIFY (uint32_t)X.d[0] +#endif + +/** + * Apply the Salsa20 core to the block provided in X ^ in. + */ +#define SALSA20_XOR_MEM(in, out) \ + XOR_X(in) \ + SALSA20(out) + +#define SALSA20 SALSA20_8 +#else /* pass 2 */ +#undef SALSA20 +#define SALSA20 SALSA20_2 +#endif + +/** + * blockmix_salsa(Bin, Bout): + * Compute Bout = BlockMix_{salsa20, 1}(Bin). The input Bin must be 128 + * bytes in length; the output Bout must also be the same size. + */ +static inline void blockmix_salsa(const salsa20_blk_t *restrict Bin, + salsa20_blk_t *restrict Bout) +{ + DECL_X + + READ_X(Bin[1]) + SALSA20_XOR_MEM(Bin[0], Bout[0]) + SALSA20_XOR_MEM(Bin[1], Bout[1]) +} + +static inline uint32_t blockmix_salsa_xor(const salsa20_blk_t *restrict Bin1, + const salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout) +{ + DECL_X + + XOR_X_2(Bin1[1], Bin2[1]) + XOR_X(Bin1[0]) + SALSA20_XOR_MEM(Bin2[0], Bout[0]) + XOR_X(Bin1[1]) + SALSA20_XOR_MEM(Bin2[1], Bout[1]) + + return INTEGERIFY; +} + +#if _YESPOWER_OPT_C_PASS_ == 1 +/* This is tunable, but it is part of what defines a yespower version */ +/* Version 0.5 */ +#define Swidth_0_5 8 +/* Version 1.0 */ +#define Swidth_1_0 11 + +/* Not tunable in this implementation, hard-coded in a few places */ +#define PWXsimple 2 +#define PWXgather 4 + +/* Derived value. Not tunable on its own. */ +#define PWXbytes (PWXgather * PWXsimple * 8) + +/* (Maybe-)runtime derived values. Not tunable on their own. */ +#define Swidth_to_Sbytes1(Swidth) ((1 << (Swidth)) * PWXsimple * 8) +#define Swidth_to_Smask(Swidth) (((1 << (Swidth)) - 1) * PWXsimple * 8) +#define Smask_to_Smask2(Smask) (((uint64_t)(Smask) << 32) | (Smask)) + +/* These should be compile-time derived */ +#define Smask2_0_5 Smask_to_Smask2(Swidth_to_Smask(Swidth_0_5)) +#define Smask2_1_0 Smask_to_Smask2(Swidth_to_Smask(Swidth_1_0)) + +typedef struct { + uint8_t *S0, *S1, *S2; + size_t w; + uint32_t Sbytes; +} pwxform_ctx_t; + +#define DECL_SMASK2REG /* empty */ +#define MAYBE_MEMORY_BARRIER /* empty */ + +#ifdef __SSE2__ +/* + * (V)PSRLDQ and (V)PSHUFD have higher throughput than (V)PSRLQ on some CPUs + * starting with Sandy Bridge. Additionally, PSHUFD uses separate source and + * destination registers, whereas the shifts would require an extra move + * instruction for our code when building without AVX. Unfortunately, PSHUFD + * is much slower on Conroe (4 cycles latency vs. 1 cycle latency for PSRLQ) + * and somewhat slower on some non-Intel CPUs (luckily not including AMD + * Bulldozer and Piledriver). + */ +#ifdef __AVX__ +#define HI32(X) \ + _mm_srli_si128((X), 4) +#elif 1 /* As an option, check for __SSE4_1__ here not to hurt Conroe */ +#define HI32(X) \ + _mm_shuffle_epi32((X), _MM_SHUFFLE(2,3,0,1)) +#else +#define HI32(X) \ + _mm_srli_epi64((X), 32) +#endif + +#if defined(__x86_64__) && \ + __GNUC__ == 4 && __GNUC_MINOR__ < 6 && !defined(__ICC) +#ifdef __AVX__ +#define MOVQ "vmovq" +#else +/* "movq" would be more correct, but "movd" is supported by older binutils + * due to an error in AMD's spec for x86-64. */ +#define MOVQ "movd" +#endif +#define EXTRACT64(X) ({ \ + uint64_t result; \ + __asm__(MOVQ " %1, %0" : "=r" (result) : "x" (X)); \ + result; \ +}) +#elif defined(__x86_64__) && !defined(_MSC_VER) && !defined(__OPEN64__) +/* MSVC and Open64 had bugs */ +#define EXTRACT64(X) _mm_cvtsi128_si64(X) +#elif defined(__x86_64__) && defined(__SSE4_1__) +/* No known bugs for this intrinsic */ +#include +#define EXTRACT64(X) _mm_extract_epi64((X), 0) +#elif defined(USE_SSE4_FOR_32BIT) && defined(__SSE4_1__) +/* 32-bit */ +#include +#if 0 +/* This is currently unused by the code below, which instead uses these two + * intrinsics explicitly when (!defined(__x86_64__) && defined(__SSE4_1__)) */ +#define EXTRACT64(X) \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ + ((uint64_t)(uint32_t)_mm_extract_epi32((X), 1) << 32)) +#endif +#else +/* 32-bit or compilers with known past bugs in _mm_cvtsi128_si64() */ +#define EXTRACT64(X) \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32)) +#endif + +#if defined(__x86_64__) && (defined(__AVX__) || !defined(__GNUC__)) +/* 64-bit with AVX */ +/* Force use of 64-bit AND instead of two 32-bit ANDs */ +#undef DECL_SMASK2REG +#if defined(__GNUC__) && !defined(__ICC) +#define DECL_SMASK2REG uint64_t Smask2reg = Smask2; +/* Force use of lower-numbered registers to reduce number of prefixes, relying + * on out-of-order execution and register renaming. */ +#define FORCE_REGALLOC_1 \ + __asm__("" : "=a" (x), "+d" (Smask2reg), "+S" (S0), "+D" (S1)); +#define FORCE_REGALLOC_2 \ + __asm__("" : : "c" (lo)); +#else +static volatile uint64_t Smask2var = Smask2; +#define DECL_SMASK2REG uint64_t Smask2reg = Smask2var; +#define FORCE_REGALLOC_1 /* empty */ +#define FORCE_REGALLOC_2 /* empty */ +#endif +#define PWXFORM_SIMD(X) { \ + uint64_t x; \ + FORCE_REGALLOC_1 \ + uint32_t lo = x = EXTRACT64(X) & Smask2reg; \ + FORCE_REGALLOC_2 \ + uint32_t hi = x >> 32; \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, *(__m128i *)(S0 + lo)); \ + X = _mm_xor_si128(X, *(__m128i *)(S1 + hi)); \ +} +#elif defined(__x86_64__) +/* 64-bit without AVX. This relies on out-of-order execution and register + * renaming. It may actually be fastest on CPUs with AVX(2) as well - e.g., + * it runs great on Haswell. */ +#warning "Note: using x86-64 inline assembly for pwxform. That's great." +#undef MAYBE_MEMORY_BARRIER +#define MAYBE_MEMORY_BARRIER \ + __asm__("" : : : "memory"); +#ifdef __ILP32__ /* x32 */ +#define REGISTER_PREFIX "e" +#else +#define REGISTER_PREFIX "r" +#endif +#define PWXFORM_SIMD(X) { \ + __m128i H; \ + __asm__( \ + "movd %0, %%rax\n\t" \ + "pshufd $0xb1, %0, %1\n\t" \ + "andq %2, %%rax\n\t" \ + "pmuludq %1, %0\n\t" \ + "movl %%eax, %%ecx\n\t" \ + "shrq $0x20, %%rax\n\t" \ + "paddq (%3,%%" REGISTER_PREFIX "cx), %0\n\t" \ + "pxor (%4,%%" REGISTER_PREFIX "ax), %0\n\t" \ + : "+x" (X), "=x" (H) \ + : "d" (Smask2), "S" (S0), "D" (S1) \ + : "cc", "ax", "cx"); \ +} +#elif defined(USE_SSE4_FOR_32BIT) && defined(__SSE4_1__) +/* 32-bit with SSE4.1 */ +#define PWXFORM_SIMD(X) { \ + __m128i x = _mm_and_si128(X, _mm_set1_epi64x(Smask2)); \ + __m128i s0 = *(__m128i *)(S0 + (uint32_t)_mm_cvtsi128_si32(x)); \ + __m128i s1 = *(__m128i *)(S1 + (uint32_t)_mm_extract_epi32(x, 1)); \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, s0); \ + X = _mm_xor_si128(X, s1); \ +} +#else +/* 32-bit without SSE4.1 */ +#define PWXFORM_SIMD(X) { \ + uint64_t x = EXTRACT64(X) & Smask2; \ + __m128i s0 = *(__m128i *)(S0 + (uint32_t)x); \ + __m128i s1 = *(__m128i *)(S1 + (x >> 32)); \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, s0); \ + X = _mm_xor_si128(X, s1); \ +} +#endif + +#define PWXFORM_SIMD_WRITE(X, Sw) \ + PWXFORM_SIMD(X) \ + MAYBE_MEMORY_BARRIER \ + *(__m128i *)(Sw + w) = X; \ + MAYBE_MEMORY_BARRIER + +#define PWXFORM_ROUND \ + PWXFORM_SIMD(X0) \ + PWXFORM_SIMD(X1) \ + PWXFORM_SIMD(X2) \ + PWXFORM_SIMD(X3) + +#define PWXFORM_ROUND_WRITE4 \ + PWXFORM_SIMD_WRITE(X0, S0) \ + PWXFORM_SIMD_WRITE(X1, S1) \ + w += 16; \ + PWXFORM_SIMD_WRITE(X2, S0) \ + PWXFORM_SIMD_WRITE(X3, S1) \ + w += 16; + +#define PWXFORM_ROUND_WRITE2 \ + PWXFORM_SIMD_WRITE(X0, S0) \ + PWXFORM_SIMD_WRITE(X1, S1) \ + w += 16; \ + PWXFORM_SIMD(X2) \ + PWXFORM_SIMD(X3) + +#else /* !defined(__SSE2__) */ + +#define PWXFORM_SIMD(x0, x1) { \ + uint64_t x = x0 & Smask2; \ + uint64_t *p0 = (uint64_t *)(S0 + (uint32_t)x); \ + uint64_t *p1 = (uint64_t *)(S1 + (x >> 32)); \ + x0 = ((x0 >> 32) * (uint32_t)x0 + p0[0]) ^ p1[0]; \ + x1 = ((x1 >> 32) * (uint32_t)x1 + p0[1]) ^ p1[1]; \ +} + +#define PWXFORM_SIMD_WRITE(x0, x1, Sw) \ + PWXFORM_SIMD(x0, x1) \ + ((uint64_t *)(Sw + w))[0] = x0; \ + ((uint64_t *)(Sw + w))[1] = x1; + +#define PWXFORM_ROUND \ + PWXFORM_SIMD(X.d[0], X.d[1]) \ + PWXFORM_SIMD(X.d[2], X.d[3]) \ + PWXFORM_SIMD(X.d[4], X.d[5]) \ + PWXFORM_SIMD(X.d[6], X.d[7]) + +#define PWXFORM_ROUND_WRITE4 \ + PWXFORM_SIMD_WRITE(X.d[0], X.d[1], S0) \ + PWXFORM_SIMD_WRITE(X.d[2], X.d[3], S1) \ + w += 16; \ + PWXFORM_SIMD_WRITE(X.d[4], X.d[5], S0) \ + PWXFORM_SIMD_WRITE(X.d[6], X.d[7], S1) \ + w += 16; + +#define PWXFORM_ROUND_WRITE2 \ + PWXFORM_SIMD_WRITE(X.d[0], X.d[1], S0) \ + PWXFORM_SIMD_WRITE(X.d[2], X.d[3], S1) \ + w += 16; \ + PWXFORM_SIMD(X.d[4], X.d[5]) \ + PWXFORM_SIMD(X.d[6], X.d[7]) +#endif + +#define PWXFORM \ + PWXFORM_ROUND PWXFORM_ROUND PWXFORM_ROUND \ + PWXFORM_ROUND PWXFORM_ROUND PWXFORM_ROUND + +#define Smask2 Smask2_0_5 + +#else /* pass 2 */ + +#undef PWXFORM +#define PWXFORM \ + PWXFORM_ROUND_WRITE4 PWXFORM_ROUND_WRITE2 PWXFORM_ROUND_WRITE2 \ + w &= Smask2; \ + { \ + uint8_t *Stmp = S2; \ + S2 = S1; \ + S1 = S0; \ + S0 = Stmp; \ + } + +#undef Smask2 +#define Smask2 Smask2_1_0 + +#endif + +/** + * blockmix_pwxform(Bin, Bout, r, S): + * Compute Bout = BlockMix_pwxform{salsa20, r, S}(Bin). The input Bin must + * be 128r bytes in length; the output Bout must also be the same size. + */ +static void blockmix(const salsa20_blk_t *restrict Bin, + salsa20_blk_t *restrict Bout, size_t r, pwxform_ctx_t *restrict ctx) +{ + if (unlikely(!ctx)) { + blockmix_salsa(Bin, Bout); + return; + } + + uint8_t *S0 = ctx->S0, *S1 = ctx->S1; +#if _YESPOWER_OPT_C_PASS_ > 1 + uint8_t *S2 = ctx->S2; + size_t w = ctx->w; +#endif + size_t i; + DECL_X + + /* Convert count of 128-byte blocks to max index of 64-byte block */ + r = r * 2 - 1; + + READ_X(Bin[r]) + + DECL_SMASK2REG + + i = 0; + do { + XOR_X(Bin[i]) + PWXFORM + if (unlikely(i >= r)) + break; + WRITE_X(Bout[i]) + i++; + } while (1); + +#if _YESPOWER_OPT_C_PASS_ > 1 + ctx->S0 = S0; ctx->S1 = S1; ctx->S2 = S2; + ctx->w = w; +#endif + + SALSA20(Bout[i]) +} + +static uint32_t blockmix_xor(const salsa20_blk_t *restrict Bin1, + const salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout, + size_t r, pwxform_ctx_t *restrict ctx) +{ + if (unlikely(!ctx)) + return blockmix_salsa_xor(Bin1, Bin2, Bout); + + uint8_t *S0 = ctx->S0, *S1 = ctx->S1; +#if _YESPOWER_OPT_C_PASS_ > 1 + uint8_t *S2 = ctx->S2; + size_t w = ctx->w; +#endif + size_t i; + DECL_X + + /* Convert count of 128-byte blocks to max index of 64-byte block */ + r = r * 2 - 1; + +#ifdef PREFETCH + PREFETCH(&Bin2[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i], _MM_HINT_T0) + } +#endif + + XOR_X_2(Bin1[r], Bin2[r]) + + DECL_SMASK2REG + + i = 0; + r--; + do { + XOR_X(Bin1[i]) + XOR_X(Bin2[i]) + PWXFORM + WRITE_X(Bout[i]) + + XOR_X(Bin1[i + 1]) + XOR_X(Bin2[i + 1]) + PWXFORM + + if (unlikely(i >= r)) + break; + + WRITE_X(Bout[i + 1]) + + i += 2; + } while (1); + i++; + +#if _YESPOWER_OPT_C_PASS_ > 1 + ctx->S0 = S0; ctx->S1 = S1; ctx->S2 = S2; + ctx->w = w; +#endif + + SALSA20(Bout[i]) + + return INTEGERIFY; +} + +static uint32_t blockmix_xor_save(salsa20_blk_t *restrict Bin1out, + salsa20_blk_t *restrict Bin2, + size_t r, pwxform_ctx_t *restrict ctx) +{ + uint8_t *S0 = ctx->S0, *S1 = ctx->S1; +#if _YESPOWER_OPT_C_PASS_ > 1 + uint8_t *S2 = ctx->S2; + size_t w = ctx->w; +#endif + size_t i; + DECL_X + DECL_Y + + /* Convert count of 128-byte blocks to max index of 64-byte block */ + r = r * 2 - 1; + +#ifdef PREFETCH + PREFETCH(&Bin2[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i], _MM_HINT_T0) + } +#endif + + XOR_X_2(Bin1out[r], Bin2[r]) + + DECL_SMASK2REG + + i = 0; + r--; + do { + XOR_X_WRITE_XOR_Y_2(Bin2[i], Bin1out[i]) + PWXFORM + WRITE_X(Bin1out[i]) + + XOR_X_WRITE_XOR_Y_2(Bin2[i + 1], Bin1out[i + 1]) + PWXFORM + + if (unlikely(i >= r)) + break; + + WRITE_X(Bin1out[i + 1]) + + i += 2; + } while (1); + i++; + +#if _YESPOWER_OPT_C_PASS_ > 1 + ctx->S0 = S0; ctx->S1 = S1; ctx->S2 = S2; + ctx->w = w; +#endif + + SALSA20(Bin1out[i]) + + return INTEGERIFY; +} + +#if _YESPOWER_OPT_C_PASS_ == 1 +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint32_t integerify(const salsa20_blk_t *B, size_t r) +{ +/* + * Our 64-bit words are in host byte order, which is why we don't just read + * w[0] here (would be wrong on big-endian). Also, our 32-bit words are + * SIMD-shuffled, but we only care about the least significant 32 bits anyway. + */ + return (uint32_t)B[2 * r - 1].d[0]; +} +#endif + +/** + * smix1(B, r, N, V, XY, S): + * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 128r+64 bytes in length. N must be even and at least 4. + * The array V must be aligned to a multiple of 64 bytes, and arrays B and XY + * to a multiple of at least 16 bytes. + */ +static void smix1(uint8_t *B, size_t r, uint32_t N, + salsa20_blk_t *V, salsa20_blk_t *XY, pwxform_ctx_t *ctx) +{ + size_t s = 2 * r; + salsa20_blk_t *X = V, *Y = &V[s], *V_j; + uint32_t i, j, n; + +#if _YESPOWER_OPT_C_PASS_ == 1 + for (i = 0; i < 2 * r; i++) { +#else + for (i = 0; i < 2; i++) { +#endif + const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64]; + salsa20_blk_t *tmp = Y; + salsa20_blk_t *dst = &X[i]; + size_t k; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + +#if _YESPOWER_OPT_C_PASS_ > 1 + for (i = 1; i < r; i++) + blockmix(&X[(i - 1) * 2], &X[i * 2], 1, ctx); +#endif + + blockmix(X, Y, r, ctx); + X = Y + s; + blockmix(Y, X, r, ctx); + j = integerify(X, r); + + for (n = 2; n < N; n <<= 1) { + uint32_t m = (n < N / 2) ? n : (N - 1 - n); + for (i = 1; i < m; i += 2) { + Y = X + s; + j &= n - 1; + j += i - 1; + V_j = &V[j * s]; + j = blockmix_xor(X, V_j, Y, r, ctx); + j &= n - 1; + j += i; + V_j = &V[j * s]; + X = Y + s; + j = blockmix_xor(Y, V_j, X, r, ctx); + } + } + n >>= 1; + + j &= n - 1; + j += N - 2 - n; + V_j = &V[j * s]; + Y = X + s; + j = blockmix_xor(X, V_j, Y, r, ctx); + j &= n - 1; + j += N - 1 - n; + V_j = &V[j * s]; + blockmix_xor(Y, V_j, XY, r, ctx); + + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = &XY[i]; + salsa20_blk_t *tmp = &XY[s]; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64]; + size_t k; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * smix2(B, r, N, Nloop, V, XY, S): + * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r bytes in length. N must be a power of 2 and at + * least 2. Nloop must be even. The array V must be aligned to a multiple of + * 64 bytes, and arrays B and XY to a multiple of at least 16 bytes. + */ +static void smix2(uint8_t *B, size_t r, uint32_t N, uint32_t Nloop, + salsa20_blk_t *V, salsa20_blk_t *XY, pwxform_ctx_t *ctx) +{ + size_t s = 2 * r; + salsa20_blk_t *X = XY, *Y = &XY[s]; + uint32_t i, j; + + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64]; + salsa20_blk_t *tmp = Y; + salsa20_blk_t *dst = &X[i]; + size_t k; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + + j = integerify(X, r) & (N - 1); + +#if _YESPOWER_OPT_C_PASS_ == 1 + if (Nloop > 2) { +#endif + do { + salsa20_blk_t *V_j = &V[j * s]; + j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1); + V_j = &V[j * s]; + j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1); + } while (Nloop -= 2); +#if _YESPOWER_OPT_C_PASS_ == 1 + } else { + const salsa20_blk_t * V_j = &V[j * s]; + j = blockmix_xor(X, V_j, Y, r, ctx) & (N - 1); + V_j = &V[j * s]; + blockmix_xor(Y, V_j, X, r, ctx); + } +#endif + + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = &X[i]; + salsa20_blk_t *tmp = Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64]; + size_t k; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * smix(B, r, N, V, XY, S): + * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * XY must be 256r bytes in length. N must be a power of 2 and at least 16. + * The array V must be aligned to a multiple of 64 bytes, and arrays B and XY + * to a multiple of at least 16 bytes (aligning them to 64 bytes as well saves + * cache lines, but it might also result in cache bank conflicts). + */ +static void smix(uint8_t *B, size_t r, uint32_t N, + salsa20_blk_t *V, salsa20_blk_t *XY, pwxform_ctx_t *ctx) +{ +#if _YESPOWER_OPT_C_PASS_ == 1 + uint32_t Nloop_all = (N + 2) / 3; /* 1/3, round up */ + uint32_t Nloop_rw = Nloop_all; + + Nloop_all++; Nloop_all &= ~(uint32_t)1; /* round up to even */ + Nloop_rw &= ~(uint32_t)1; /* round down to even */ +#else + uint32_t Nloop_rw = (N + 2) / 3; /* 1/3, round up */ + Nloop_rw++; Nloop_rw &= ~(uint32_t)1; /* round up to even */ +#endif + + smix1(B, 1, ctx->Sbytes / 128, (salsa20_blk_t *)ctx->S0, XY, NULL); + smix1(B, r, N, V, XY, ctx); + smix2(B, r, N, Nloop_rw /* must be > 2 */, V, XY, ctx); +#if _YESPOWER_OPT_C_PASS_ == 1 + if (Nloop_all > Nloop_rw) + smix2(B, r, N, 2, V, XY, ctx); +#endif +} + +#if _YESPOWER_OPT_C_PASS_ == 1 +#undef _YESPOWER_OPT_C_PASS_ +#define _YESPOWER_OPT_C_PASS_ 2 +#define blockmix_salsa blockmix_salsa_1_0 +#define blockmix_salsa_xor blockmix_salsa_xor_1_0 +#define blockmix blockmix_1_0 +#define blockmix_xor blockmix_xor_1_0 +#define blockmix_xor_save blockmix_xor_save_1_0 +#define smix1 smix1_1_0 +#define smix2 smix2_1_0 +#define smix smix_1_0 +#include "yespower.c" +#undef smix + +/** + * yespower(local, src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * local is the thread-local data structure, allowing to preserve and reuse a + * memory allocation across calls, thereby reducing its overhead. + * + * Return 0 on success; or -1 on error. + */ +int yespower(yespower_local_t *local, + const uint8_t *src, size_t srclen, + const yespower_params_t *params, + yespower_binary_t *dst) +{ + yespower_version_t version = params->version; + uint32_t N = params->N; + uint32_t r = params->r; + const uint8_t *pers = params->pers; + size_t perslen = params->perslen; + uint32_t Swidth; + size_t B_size, V_size, XY_size, need; + uint8_t *B, *S; + salsa20_blk_t *V, *XY; + pwxform_ctx_t ctx; + uint8_t sha256[32]; + + /* Sanity-check parameters */ + if ((version != YESPOWER_0_5 && version != YESPOWER_1_0) || + N < 1024 || N > 512 * 1024 || r < 8 || r > 32 || + (N & (N - 1)) != 0 || + (!pers && perslen)) { + errno = EINVAL; + goto fail; + } + + /* Allocate memory */ + B_size = (size_t)128 * r; + V_size = B_size * N; + if (version == YESPOWER_0_5) { + XY_size = B_size * 2; + Swidth = Swidth_0_5; + ctx.Sbytes = 2 * Swidth_to_Sbytes1(Swidth); + } else { + XY_size = B_size + 64; + Swidth = Swidth_1_0; + ctx.Sbytes = 3 * Swidth_to_Sbytes1(Swidth); + } + need = B_size + V_size + XY_size + ctx.Sbytes; + if (local->aligned_size < need) { + if (free_region(local)) + goto fail; + if (!alloc_region(local, need)) + goto fail; + } + B = (uint8_t *)local->aligned; + V = (salsa20_blk_t *)((uint8_t *)B + B_size); + XY = (salsa20_blk_t *)((uint8_t *)V + V_size); + S = (uint8_t *)XY + XY_size; + ctx.S0 = S; + ctx.S1 = S + Swidth_to_Sbytes1(Swidth); + + SHA256_Buf(src, srclen, sha256); + + if (version == YESPOWER_0_5) { + PBKDF2_SHA256(sha256, sizeof(sha256), src, srclen, 1, + B, B_size); + memcpy(sha256, B, sizeof(sha256)); + smix(B, r, N, V, XY, &ctx); + PBKDF2_SHA256(sha256, sizeof(sha256), B, B_size, 1, + (uint8_t *)dst, sizeof(*dst)); + + if (pers) { + HMAC_SHA256_Buf(dst, sizeof(*dst), pers, perslen, + sha256); + SHA256_Buf(sha256, sizeof(sha256), (uint8_t *)dst); + } + } else { + ctx.S2 = S + 2 * Swidth_to_Sbytes1(Swidth); + ctx.w = 0; + + if (pers) { + src = pers; + srclen = perslen; + } else { + srclen = 0; + } + + PBKDF2_SHA256(sha256, sizeof(sha256), src, srclen, 1, B, 128); + memcpy(sha256, B, sizeof(sha256)); + smix_1_0(B, r, N, V, XY, &ctx); + HMAC_SHA256_Buf(B + B_size - 64, 64, + sha256, sizeof(sha256), (uint8_t *)dst); + } + + /* Success! */ + return 0; + +fail: + memset(dst, 0xff, sizeof(*dst)); + return -1; +} + +#ifndef thread_local +# if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__ +# define thread_local _Thread_local +# elif defined _WIN32 && ( \ + defined _MSC_VER || \ + defined __ICL || \ + defined __DMC__ || \ + defined __BORLANDC__ ) +# define thread_local __declspec(thread) +/* note that ICC (linux) and Clang are covered by __GNUC__ */ +# elif defined __GNUC__ || \ + defined __SUNPRO_C || \ + defined __xlC__ +# define thread_local __thread +# else +# error "Cannot define thread_local" +# endif +#endif + +/** + * yespower_tls(src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * The memory allocation is maintained internally using thread-local storage. + * + * Return 0 on success; or -1 on error. + */ +int yespower_tls(const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst) +{ + static thread_local int initialized = 0; + static thread_local yespower_local_t local; + + if (!initialized) { + init_region(&local); + initialized = 1; + } + + return yespower(&local, src, srclen, params, dst); +} + +int yespower_init_local(yespower_local_t *local) +{ + init_region(local); + return 0; +} + +int yespower_free_local(yespower_local_t *local) +{ + return free_region(local); +} +#endif \ No newline at end of file diff --git a/src/Native/libmultihash/minotaur/crypto/yespower.h b/src/Native/libmultihash/minotaur/crypto/yespower.h new file mode 100644 index 000000000..55c36ce9f --- /dev/null +++ b/src/Native/libmultihash/minotaur/crypto/yespower.h @@ -0,0 +1,130 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013-2018 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _YESPOWER_H_ +#define _YESPOWER_H_ + +#include +#include /* for size_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Internal type used by the memory allocator. Please do not use it directly. + * Use yespower_local_t instead. + */ +typedef struct { + void *base, *aligned; + size_t base_size, aligned_size; +} yespower_region_t; + +/** + * Type for thread-local (RAM) data structure. + */ +typedef yespower_region_t yespower_local_t; + +/* + * Type for yespower algorithm version numbers. + */ +typedef enum { YESPOWER_0_5 = 5, YESPOWER_1_0 = 10 } yespower_version_t; + +/** + * yespower parameters combined into one struct. + */ +typedef struct { + yespower_version_t version; + uint32_t N, r; + const uint8_t *pers; + size_t perslen; +} yespower_params_t; + +/** + * A 256-bit yespower hash. + */ +typedef struct { + unsigned char uc[32]; +} yespower_binary_t; + +/** + * yespower_init_local(local): + * Initialize the thread-local (RAM) data structure. Actual memory allocation + * is currently fully postponed until a call to yespower(). + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yespower_init_local(yespower_local_t *local); + +/** + * yespower_free_local(local): + * Free memory that may have been allocated for an initialized thread-local + * (RAM) data structure. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yespower_free_local(yespower_local_t *local); + +/** + * yespower(local, src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * local is the thread-local data structure, allowing to preserve and reuse a + * memory allocation across calls, thereby reducing processing overhead. + * + * Return 0 on success; or -1 on error. + * + * local must be initialized with yespower_init_local(). + * + * MT-safe as long as local and dst are local to the thread. + */ +extern int yespower(yespower_local_t *local, + const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst); + +/** + * yespower_tls(src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * The memory allocation is maintained internally using thread-local storage. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as dst is local to the thread. + */ +extern int yespower_tls(const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst); + +#ifdef __cplusplus +} +#endif + +#endif /* !_YESPOWER_H_ */ \ No newline at end of file diff --git a/src/Native/libmultihash/minotaur/minotaurx.c b/src/Native/libmultihash/minotaur/minotaurx.c new file mode 100644 index 000000000..2f3484559 --- /dev/null +++ b/src/Native/libmultihash/minotaur/minotaurx.c @@ -0,0 +1,241 @@ +// Copyright (c) 2019-2021 The Litecoin Cash Core developers +// Copyright (c) 2022 The Avian Core developers +// Copyright (c) 2022 Shafil Alam +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "crypto/yespower.h" + +#include +#include +#include +#include + +#include "../sha3/sph_blake.h" +#include "../sha3/sph_bmw.h" +#include "../sha3/sph_groestl.h" +#include "../sha3/sph_jh.h" +#include "../sha3/sph_keccak.h" +#include "../sha3/sph_skein.h" +#include "../sha3/sph_luffa.h" +#include "../sha3/sph_cubehash.h" +#include "../sha3/sph_shavite.h" +#include "../sha3/sph_simd.h" +#include "../sha3/sph_echo.h" +#include "../sha3/sph_hamsi.h" +#include "../sha3/sph_fugue.h" +#include "../sha3/sph_shabal.h" +#include "../sha3/sph_whirlpool.h" +#include "../sha3/sph_sha2.h" + +#include "crypto/yespower.h" + +// Config +#define MINOTAUR_ALGO_COUNT 16 +static const yespower_params_t yespower_params = {YESPOWER_1_0, 2048, 8, "et in arcadia ego", 17}; + +typedef struct TortureNode TortureNode; +typedef struct TortureGarden TortureGarden; + +// Graph of hash algos plus SPH contexts +struct TortureGarden { + sph_blake512_context context_blake; + sph_bmw512_context context_bmw; + sph_cubehash512_context context_cubehash; + sph_echo512_context context_echo; + sph_fugue512_context context_fugue; + sph_groestl512_context context_groestl; + sph_hamsi512_context context_hamsi; + sph_jh512_context context_jh; + sph_keccak512_context context_keccak; + sph_luffa512_context context_luffa; + sph_shabal512_context context_shabal; + sph_shavite512_context context_shavite; + sph_simd512_context context_simd; + sph_skein512_context context_skein; + sph_whirlpool_context context_whirlpool; + sph_sha512_context context_sha2; + + struct TortureNode { + unsigned int algo; + TortureNode *childLeft; + TortureNode *childRight; + } nodes[22]; +}; + +#if defined(_MSC_VER) +#define _ALIGN(x) __declspec(align(x)) +#else +#define _ALIGN(x) __attribute__ ((aligned(x))) +#endif + +// Get a 64-byte hash for given 64-byte input, using given TortureGarden contexts and given algo index +void get_hash(void *output, const void *input, TortureGarden *garden, unsigned int algo) +{ + unsigned char _ALIGN(64) hash[64]; + memset(hash, 0, sizeof(hash)); // Doesn't affect Minotaur as all hash outputs are 64 bytes; required for MinotaurX due to yespower's 32 byte output. + + switch (algo) { + case 0: + sph_blake512_init(&garden->context_blake); + sph_blake512(&garden->context_blake, input, 64); + sph_blake512_close(&garden->context_blake, hash); + break; + case 1: + sph_bmw512_init(&garden->context_bmw); + sph_bmw512(&garden->context_bmw, input, 64); + sph_bmw512_close(&garden->context_bmw, hash); + break; + case 2: + sph_cubehash512_init(&garden->context_cubehash); + sph_cubehash512(&garden->context_cubehash, input, 64); + sph_cubehash512_close(&garden->context_cubehash, hash); + break; + case 3: + sph_echo512_init(&garden->context_echo); + sph_echo512(&garden->context_echo, input, 64); + sph_echo512_close(&garden->context_echo, hash); + break; + case 4: + sph_fugue512_init(&garden->context_fugue); + sph_fugue512(&garden->context_fugue, input, 64); + sph_fugue512_close(&garden->context_fugue, hash); + break; + case 5: + sph_groestl512_init(&garden->context_groestl); + sph_groestl512(&garden->context_groestl, input, 64); + sph_groestl512_close(&garden->context_groestl, hash); + break; + case 6: + sph_hamsi512_init(&garden->context_hamsi); + sph_hamsi512(&garden->context_hamsi, input, 64); + sph_hamsi512_close(&garden->context_hamsi, hash); + break; + case 7: + sph_sha512_init(&garden->context_sha2); + sph_sha512(&garden->context_sha2, input, 64); + sph_sha512_close(&garden->context_sha2, hash); + break; + case 8: + sph_jh512_init(&garden->context_jh); + sph_jh512(&garden->context_jh, input, 64); + sph_jh512_close(&garden->context_jh, hash); + break; + case 9: + sph_keccak512_init(&garden->context_keccak); + sph_keccak512(&garden->context_keccak, input, 64); + sph_keccak512_close(&garden->context_keccak, hash); + break; + case 10: + sph_luffa512_init(&garden->context_luffa); + sph_luffa512(&garden->context_luffa, input, 64); + sph_luffa512_close(&garden->context_luffa, hash); + break; + case 11: + sph_shabal512_init(&garden->context_shabal); + sph_shabal512(&garden->context_shabal, input, 64); + sph_shabal512_close(&garden->context_shabal, hash); + break; + case 12: + sph_shavite512_init(&garden->context_shavite); + sph_shavite512(&garden->context_shavite, input, 64); + sph_shavite512_close(&garden->context_shavite, hash); + break; + case 13: + sph_simd512_init(&garden->context_simd); + sph_simd512(&garden->context_simd, input, 64); + sph_simd512_close(&garden->context_simd, hash); + break; + case 14: + sph_skein512_init(&garden->context_skein); + sph_skein512(&garden->context_skein, input, 64); + sph_skein512_close(&garden->context_skein, hash); + break; + case 15: + sph_whirlpool_init(&garden->context_whirlpool); + sph_whirlpool(&garden->context_whirlpool, input, 64); + sph_whirlpool_close(&garden->context_whirlpool, hash); + break; + // NB: The CPU-hard gate must be case MINOTAUR_ALGO_COUNT. + case 16: + yespower_tls(input, 64, &yespower_params, (yespower_binary_t*)hash); + } + + // Output the hash + memcpy(output, hash, 64); +} + +// Recursively traverse a given torture garden starting with a given hash and given node within the garden. The hash is overwritten with the final hash. +void traverse_garden(TortureGarden *garden, void *hash, TortureNode *node) +{ + unsigned char _ALIGN(64) partialHash[64]; + memset(partialHash, 0, sizeof(partialHash)); // Doesn't affect Minotaur as all hash outputs are 64 bytes; required for MinotaurX due to yespower's 32 byte output. + get_hash(partialHash, hash, garden, node->algo); + + if (partialHash[63] % 2 == 0) { // Last byte of output hash is even + if (node->childLeft != NULL) + traverse_garden(garden, partialHash, node->childLeft); + } else { // Last byte of output hash is odd + if (node->childRight != NULL) + traverse_garden(garden, partialHash, node->childRight); + } + + memcpy(hash, partialHash, 64); +} + +// Associate child nodes with a parent node +inline void link_nodes(TortureNode *parent, TortureNode *childLeft, TortureNode *childRight) +{ + parent->childLeft = childLeft; + parent->childRight = childRight; +} + +// Produce a 32-byte hash from 80-byte input data +void minotaurx_hash(const char *input, char *output) +{ + // Create torture garden nodes. Note that both sides of 19 and 20 lead to 21, and 21 has no children (to make traversal complete). + // The successful path through the garden visits 7 nodes. + TortureGarden garden; + link_nodes(&garden.nodes[0], &garden.nodes[1], &garden.nodes[2]); + link_nodes(&garden.nodes[1], &garden.nodes[3], &garden.nodes[4]); + link_nodes(&garden.nodes[2], &garden.nodes[5], &garden.nodes[6]); + link_nodes(&garden.nodes[3], &garden.nodes[7], &garden.nodes[8]); + link_nodes(&garden.nodes[4], &garden.nodes[9], &garden.nodes[10]); + link_nodes(&garden.nodes[5], &garden.nodes[11], &garden.nodes[12]); + link_nodes(&garden.nodes[6], &garden.nodes[13], &garden.nodes[14]); + link_nodes(&garden.nodes[7], &garden.nodes[15], &garden.nodes[16]); + link_nodes(&garden.nodes[8], &garden.nodes[15], &garden.nodes[16]); + link_nodes(&garden.nodes[9], &garden.nodes[15], &garden.nodes[16]); + link_nodes(&garden.nodes[10], &garden.nodes[15], &garden.nodes[16]); + link_nodes(&garden.nodes[11], &garden.nodes[17], &garden.nodes[18]); + link_nodes(&garden.nodes[12], &garden.nodes[17], &garden.nodes[18]); + link_nodes(&garden.nodes[13], &garden.nodes[17], &garden.nodes[18]); + link_nodes(&garden.nodes[14], &garden.nodes[17], &garden.nodes[18]); + link_nodes(&garden.nodes[15], &garden.nodes[19], &garden.nodes[20]); + link_nodes(&garden.nodes[16], &garden.nodes[19], &garden.nodes[20]); + link_nodes(&garden.nodes[17], &garden.nodes[19], &garden.nodes[20]); + link_nodes(&garden.nodes[18], &garden.nodes[19], &garden.nodes[20]); + link_nodes(&garden.nodes[19], &garden.nodes[21], &garden.nodes[21]); + link_nodes(&garden.nodes[20], &garden.nodes[21], &garden.nodes[21]); + garden.nodes[21].childLeft = NULL; + garden.nodes[21].childRight = NULL; + + // Find initial sha512 hash + unsigned char _ALIGN(64) hash[64]; + sph_sha512_init(&garden.context_sha2); + sph_sha512(&garden.context_sha2, input, 80); + sph_sha512_close(&garden.context_sha2, hash); + + // Assign algos to torture garden nodes based on initial hash + for (int i = 0; i < 22; i++) + garden.nodes[i].algo = hash[i] % MINOTAUR_ALGO_COUNT; + + // Hardened garden gates on MinotaurX + garden.nodes[21].algo = MINOTAUR_ALGO_COUNT; + + // Send the initial hash through the torture garden + traverse_garden(&garden, hash, &garden.nodes[0]); + + // Truncate the result to 32 bytes + memcpy(output, hash, 32); +} diff --git a/src/Native/libmultihash/minotaur/minotaurx.h b/src/Native/libmultihash/minotaur/minotaurx.h new file mode 100644 index 000000000..a7380416f --- /dev/null +++ b/src/Native/libmultihash/minotaur/minotaurx.h @@ -0,0 +1,16 @@ +#ifndef MINOTAURX_H +#define MINOTAURX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void minotaurx_hash(const char* input, char* output); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/Native/libverushash/Makefile b/src/Native/libverushash/Makefile new file mode 100644 index 000000000..3ac876e32 --- /dev/null +++ b/src/Native/libverushash/Makefile @@ -0,0 +1,17 @@ +CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable -msse4 -msse4.1 -msse4.2 -mssse3 -mavx -mpclmul -maes +CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -faligned-new -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 -msse4 -msse4.1 -msse4.2 -mssse3 -mavx -mpclmul -maes +LDFLAGS = -shared +LDLIBS = -lsodium +TARGET = libverushash.so + +OBJECTS = crypto/haraka.o crypto/haraka_portable.o crypto/ripemd160.o crypto/sha256.o crypto/uint256.o crypto/utilstrencodings.o crypto/verus_hash.o crypto/verus_clhash.o crypto/verus_clhash_portable.o exports.o verushashverify.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libverushash/crypto/common.h b/src/Native/libverushash/crypto/common.h new file mode 100644 index 000000000..c2fc1cd1d --- /dev/null +++ b/src/Native/libverushash/crypto/common.h @@ -0,0 +1,114 @@ +// 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_COMMON_H +#define BITCOIN_CRYPTO_COMMON_H + +#if defined(HAVE_CONFIG_H) +#include "bitcoin-config.h" +#endif + +#include +#include + +#include "../sodium.h" +#ifdef WIN32 +#include "compat/endian.h" +#else +#include +#endif + +//#if defined(NDEBUG) +//# error "Bitcoin cannot be compiled without assertions." +//#endif + +uint16_t static inline ReadLE16(const unsigned char* ptr) +{ + return le16toh(*((uint16_t*)ptr)); +} + +uint32_t static inline ReadLE32(const unsigned char* ptr) +{ + return le32toh(*((uint32_t*)ptr)); +} + +uint64_t static inline ReadLE64(const unsigned char* ptr) +{ + return le64toh(*((uint64_t*)ptr)); +} + +void static inline WriteLE16(unsigned char* ptr, uint16_t x) +{ + *((uint16_t*)ptr) = htole16(x); +} + +void static inline WriteLE32(unsigned char* ptr, uint32_t x) +{ + *((uint32_t*)ptr) = htole32(x); +} + +void static inline WriteLE64(unsigned char* ptr, uint64_t x) +{ + *((uint64_t*)ptr) = htole64(x); +} + +uint32_t static inline ReadBE32(const unsigned char* ptr) +{ + return be32toh(*((uint32_t*)ptr)); +} + +uint64_t static inline ReadBE64(const unsigned char* ptr) +{ + return be64toh(*((uint64_t*)ptr)); +} + +void static inline WriteBE32(unsigned char* ptr, uint32_t x) +{ + *((uint32_t*)ptr) = htobe32(x); +} + +void static inline WriteBE64(unsigned char* ptr, uint64_t x) +{ + *((uint64_t*)ptr) = htobe64(x); +} + +/*int inline init_and_check_sodium() +{ + if (sodium_init() == -1) { + return -1; + } + + // What follows is a runtime test that ensures the version of libsodium + // we're linked against checks that signatures are canonical (s < L). + const unsigned char message[1] = { 0 }; + + unsigned char pk[crypto_sign_PUBLICKEYBYTES]; + unsigned char sk[crypto_sign_SECRETKEYBYTES]; + unsigned char sig[crypto_sign_BYTES]; + + crypto_sign_keypair(pk, sk); + crypto_sign_detached(sig, NULL, message, sizeof(message), sk); + + assert(crypto_sign_verify_detached(sig, message, sizeof(message), pk) == 0); + + // Copied from libsodium/crypto_sign/ed25519/ref10/open.c + static const unsigned char L[32] = + { 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }; + + // Add L to S, which starts at sig[32]. + unsigned int s = 0; + for (size_t i = 0; i < 32; i++) { + s = sig[32 + i] + L[i] + (s >> 8); + sig[32 + i] = s & 0xff; + } + + assert(crypto_sign_verify_detached(sig, message, sizeof(message), pk) != 0); + + return 0; +}*/ + +#endif // BITCOIN_CRYPTO_COMMON_H \ No newline at end of file diff --git a/src/Native/libverushash/crypto/haraka.c b/src/Native/libverushash/crypto/haraka.c new file mode 100644 index 000000000..49fb4196b --- /dev/null +++ b/src/Native/libverushash/crypto/haraka.c @@ -0,0 +1,665 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 kste + +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. + +Optimized Implementations for Haraka256 and Haraka512 +*/ + +#include +#include "haraka.h" + +u128 rc[40]; +u128 rc0[40] = {0}; + +void load_constants() { + rc[0] = _mm_set_epi32(0x0684704c,0xe620c00a,0xb2c5fef0,0x75817b9d); + rc[1] = _mm_set_epi32(0x8b66b4e1,0x88f3a06b,0x640f6ba4,0x2f08f717); + rc[2] = _mm_set_epi32(0x3402de2d,0x53f28498,0xcf029d60,0x9f029114); + rc[3] = _mm_set_epi32(0x0ed6eae6,0x2e7b4f08,0xbbf3bcaf,0xfd5b4f79); + rc[4] = _mm_set_epi32(0xcbcfb0cb,0x4872448b,0x79eecd1c,0xbe397044); + rc[5] = _mm_set_epi32(0x7eeacdee,0x6e9032b7,0x8d5335ed,0x2b8a057b); + rc[6] = _mm_set_epi32(0x67c28f43,0x5e2e7cd0,0xe2412761,0xda4fef1b); + rc[7] = _mm_set_epi32(0x2924d9b0,0xafcacc07,0x675ffde2,0x1fc70b3b); + rc[8] = _mm_set_epi32(0xab4d63f1,0xe6867fe9,0xecdb8fca,0xb9d465ee); + rc[9] = _mm_set_epi32(0x1c30bf84,0xd4b7cd64,0x5b2a404f,0xad037e33); + rc[10] = _mm_set_epi32(0xb2cc0bb9,0x941723bf,0x69028b2e,0x8df69800); + rc[11] = _mm_set_epi32(0xfa0478a6,0xde6f5572,0x4aaa9ec8,0x5c9d2d8a); + rc[12] = _mm_set_epi32(0xdfb49f2b,0x6b772a12,0x0efa4f2e,0x29129fd4); + rc[13] = _mm_set_epi32(0x1ea10344,0xf449a236,0x32d611ae,0xbb6a12ee); + rc[14] = _mm_set_epi32(0xaf044988,0x4b050084,0x5f9600c9,0x9ca8eca6); + rc[15] = _mm_set_epi32(0x21025ed8,0x9d199c4f,0x78a2c7e3,0x27e593ec); + rc[16] = _mm_set_epi32(0xbf3aaaf8,0xa759c9b7,0xb9282ecd,0x82d40173); + rc[17] = _mm_set_epi32(0x6260700d,0x6186b017,0x37f2efd9,0x10307d6b); + rc[18] = _mm_set_epi32(0x5aca45c2,0x21300443,0x81c29153,0xf6fc9ac6); + rc[19] = _mm_set_epi32(0x9223973c,0x226b68bb,0x2caf92e8,0x36d1943a); + rc[20] = _mm_set_epi32(0xd3bf9238,0x225886eb,0x6cbab958,0xe51071b4); + rc[21] = _mm_set_epi32(0xdb863ce5,0xaef0c677,0x933dfddd,0x24e1128d); + rc[22] = _mm_set_epi32(0xbb606268,0xffeba09c,0x83e48de3,0xcb2212b1); + rc[23] = _mm_set_epi32(0x734bd3dc,0xe2e4d19c,0x2db91a4e,0xc72bf77d); + rc[24] = _mm_set_epi32(0x43bb47c3,0x61301b43,0x4b1415c4,0x2cb3924e); + rc[25] = _mm_set_epi32(0xdba775a8,0xe707eff6,0x03b231dd,0x16eb6899); + rc[26] = _mm_set_epi32(0x6df3614b,0x3c755977,0x8e5e2302,0x7eca472c); + rc[27] = _mm_set_epi32(0xcda75a17,0xd6de7d77,0x6d1be5b9,0xb88617f9); + rc[28] = _mm_set_epi32(0xec6b43f0,0x6ba8e9aa,0x9d6c069d,0xa946ee5d); + rc[29] = _mm_set_epi32(0xcb1e6950,0xf957332b,0xa2531159,0x3bf327c1); + rc[30] = _mm_set_epi32(0x2cee0c75,0x00da619c,0xe4ed0353,0x600ed0d9); + rc[31] = _mm_set_epi32(0xf0b1a5a1,0x96e90cab,0x80bbbabc,0x63a4a350); + rc[32] = _mm_set_epi32(0xae3db102,0x5e962988,0xab0dde30,0x938dca39); + rc[33] = _mm_set_epi32(0x17bb8f38,0xd554a40b,0x8814f3a8,0x2e75b442); + rc[34] = _mm_set_epi32(0x34bb8a5b,0x5f427fd7,0xaeb6b779,0x360a16f6); + rc[35] = _mm_set_epi32(0x26f65241,0xcbe55438,0x43ce5918,0xffbaafde); + rc[36] = _mm_set_epi32(0x4ce99a54,0xb9f3026a,0xa2ca9cf7,0x839ec978); + rc[37] = _mm_set_epi32(0xae51a51a,0x1bdff7be,0x40c06e28,0x22901235); + rc[38] = _mm_set_epi32(0xa0c1613c,0xba7ed22b,0xc173bc0f,0x48a659cf); + rc[39] = _mm_set_epi32(0x756acc03,0x02288288,0x4ad6bdfd,0xe9c59da1); +} + +void test_implementations() { + unsigned char *in = (unsigned char *)calloc(64*8, sizeof(unsigned char)); + unsigned char *out256 = (unsigned char *)calloc(32*8, sizeof(unsigned char)); + unsigned char *out512 = (unsigned char *)calloc(32*8, sizeof(unsigned char)); + unsigned char testvector256[32] = {0x80, 0x27, 0xcc, 0xb8, 0x79, 0x49, 0x77, 0x4b, + 0x78, 0xd0, 0x54, 0x5f, 0xb7, 0x2b, 0xf7, 0x0c, + 0x69, 0x5c, 0x2a, 0x09, 0x23, 0xcb, 0xd4, 0x7b, + 0xba, 0x11, 0x59, 0xef, 0xbf, 0x2b, 0x2c, 0x1c}; + + unsigned char testvector512[32] = {0xbe, 0x7f, 0x72, 0x3b, 0x4e, 0x80, 0xa9, 0x98, + 0x13, 0xb2, 0x92, 0x28, 0x7f, 0x30, 0x6f, 0x62, + 0x5a, 0x6d, 0x57, 0x33, 0x1c, 0xae, 0x5f, 0x34, + 0xdd, 0x92, 0x77, 0xb0, 0x94, 0x5b, 0xe2, 0xaa}; + + + + int i; + + // Input for testvector + for(i = 0; i < 512; i++) { + in[i] = i % 64; + } + + load_constants(); + haraka512_8x(out512, in); + + // Verify output + for(i = 0; i < 32; i++) { + if (out512[i % 32] != testvector512[i]) { + printf("Error: testvector incorrect.\n"); + return; + } + } + + free(in); + free(out256); + free(out512); +} + +void haraka256(unsigned char *out, const unsigned char *in) { + __m128i s[2], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + + AES2(s[0], s[1], 0); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 4); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 8); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 12); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 16); + MIX2(s[0], s[1]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + + STORE(out, s[0]); + STORE(out + 16, s[1]); +} + +void haraka256_keyed(unsigned char *out, const unsigned char *in, const u128 *rc) { + __m128i s[2], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + + AES2(s[0], s[1], 0); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 4); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 8); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 12); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 16); + MIX2(s[0], s[1]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + + STORE(out, s[0]); + STORE(out + 16, s[1]); +} + +void haraka256_4x(unsigned char *out, const unsigned char *in) { + __m128i s[4][2], tmp; + + s[0][0] = LOAD(in); + s[0][1] = LOAD(in + 16); + s[1][0] = LOAD(in + 32); + s[1][1] = LOAD(in + 48); + s[2][0] = LOAD(in + 64); + s[2][1] = LOAD(in + 80); + s[3][0] = LOAD(in + 96); + s[3][1] = LOAD(in + 112); + + // Round 1 + AES2_4x(s[0], s[1], s[2], s[3], 0); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 2 + AES2_4x(s[0], s[1], s[2], s[3], 4); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 3 + AES2_4x(s[0], s[1], s[2], s[3], 8); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 4 + AES2_4x(s[0], s[1], s[2], s[3], 12); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 5 + AES2_4x(s[0], s[1], s[2], s[3], 16); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Feed Forward + s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32)); + s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48)); + s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64)); + s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80)); + s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96)); + s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112)); + + STORE(out, s[0][0]); + STORE(out + 16, s[0][1]); + STORE(out + 32, s[1][0]); + STORE(out + 48, s[1][1]); + STORE(out + 64, s[2][0]); + STORE(out + 80, s[2][1]); + STORE(out + 96, s[3][0]); + STORE(out + 112, s[3][1]); +} + +void haraka256_8x(unsigned char *out, const unsigned char *in) { + // This is faster on Skylake, the code below is faster on Haswell. + haraka256_4x(out, in); + haraka256_4x(out + 128, in + 128); + return; + // __m128i s[8][2], tmp; + // + // int i; + // + // s[0][0] = LOAD(in); + // s[0][1] = LOAD(in + 16); + // s[1][0] = LOAD(in + 32); + // s[1][1] = LOAD(in + 48); + // s[2][0] = LOAD(in + 64); + // s[2][1] = LOAD(in + 80); + // s[3][0] = LOAD(in + 96); + // s[3][1] = LOAD(in + 112); + // s[4][0] = LOAD(in + 128); + // s[4][1] = LOAD(in + 144); + // s[5][0] = LOAD(in + 160); + // s[5][1] = LOAD(in + 176); + // s[6][0] = LOAD(in + 192); + // s[6][1] = LOAD(in + 208); + // s[7][0] = LOAD(in + 224); + // s[7][1] = LOAD(in + 240); + // + // // Round 1 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // + // // Round 2 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 4); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Round 3 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Round 4 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 12); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Round 5 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Feed Forward + // s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + // s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + // s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32)); + // s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48)); + // s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64)); + // s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80)); + // s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96)); + // s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112)); + // s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 128)); + // s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 144)); + // s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 160)); + // s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 176)); + // s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 192)); + // s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 208)); + // s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 224)); + // s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 240)); + // + // STORE(out, s[0][0]); + // STORE(out + 16, s[0][1]); + // STORE(out + 32, s[1][0]); + // STORE(out + 48, s[1][1]); + // STORE(out + 64, s[2][0]); + // STORE(out + 80, s[2][1]); + // STORE(out + 96, s[3][0]); + // STORE(out + 112, s[3][1]); + // STORE(out + 128, s[4][0]); + // STORE(out + 144, s[4][1]); + // STORE(out + 160, s[5][0]); + // STORE(out + 176, s[5][1]); + // STORE(out + 192, s[6][0]); + // STORE(out + 208, s[6][1]); + // STORE(out + 224, s[7][0]); + // STORE(out + 240, s[7][1]); +} + +void haraka512(unsigned char *out, const unsigned char *in) { + u128 s[4], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + s[2] = LOAD(in + 32); + s[3] = LOAD(in + 48); + + AES4(s[0], s[1], s[2], s[3], 0); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 8); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 16); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 24); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 32); + MIX4(s[0], s[1], s[2], s[3]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + s[2] = _mm_xor_si128(s[2], LOAD(in + 32)); + s[3] = _mm_xor_si128(s[3], LOAD(in + 48)); + + TRUNCSTORE(out, s[0], s[1], s[2], s[3]); +} + +void haraka512_zero(unsigned char *out, const unsigned char *in) { + u128 s[4], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + s[2] = LOAD(in + 32); + s[3] = LOAD(in + 48); + + AES4_zero(s[0], s[1], s[2], s[3], 0); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 8); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 16); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 24); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 32); + MIX4(s[0], s[1], s[2], s[3]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + s[2] = _mm_xor_si128(s[2], LOAD(in + 32)); + s[3] = _mm_xor_si128(s[3], LOAD(in + 48)); + + TRUNCSTORE(out, s[0], s[1], s[2], s[3]); +} + +void haraka512_keyed(unsigned char *out, const unsigned char *in, const u128 *rc) { + u128 s[4], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + s[2] = LOAD(in + 32); + s[3] = LOAD(in + 48); + + AES4(s[0], s[1], s[2], s[3], 0); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 8); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 16); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 24); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 32); + MIX4(s[0], s[1], s[2], s[3]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + s[2] = _mm_xor_si128(s[2], LOAD(in + 32)); + s[3] = _mm_xor_si128(s[3], LOAD(in + 48)); + + TRUNCSTORE(out, s[0], s[1], s[2], s[3]); +} + +void haraka512_4x(unsigned char *out, const unsigned char *in) { + u128 s[4][4], tmp; + + s[0][0] = LOAD(in); + s[0][1] = LOAD(in + 16); + s[0][2] = LOAD(in + 32); + s[0][3] = LOAD(in + 48); + s[1][0] = LOAD(in + 64); + s[1][1] = LOAD(in + 80); + s[1][2] = LOAD(in + 96); + s[1][3] = LOAD(in + 112); + s[2][0] = LOAD(in + 128); + s[2][1] = LOAD(in + 144); + s[2][2] = LOAD(in + 160); + s[2][3] = LOAD(in + 176); + s[3][0] = LOAD(in + 192); + s[3][1] = LOAD(in + 208); + s[3][2] = LOAD(in + 224); + s[3][3] = LOAD(in + 240); + + AES4_4x(s[0], s[1], s[2], s[3], 0); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 8); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 16); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 24); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 32); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + + s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32)); + s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48)); + s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64)); + s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80)); + s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96)); + s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112)); + s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128)); + s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144)); + s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160)); + s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176)); + s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192)); + s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208)); + s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224)); + s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240)); + + TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]); + TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]); + TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]); + TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]); +} + +void haraka512_8x(unsigned char *out, const unsigned char *in) { + // This is faster on Skylake, the code below is faster on Haswell. + haraka512_4x(out, in); + haraka512_4x(out + 128, in + 256); + + // u128 s[8][4], tmp; + // + // s[0][0] = LOAD(in); + // s[0][1] = LOAD(in + 16); + // s[0][2] = LOAD(in + 32); + // s[0][3] = LOAD(in + 48); + // s[1][0] = LOAD(in + 64); + // s[1][1] = LOAD(in + 80); + // s[1][2] = LOAD(in + 96); + // s[1][3] = LOAD(in + 112); + // s[2][0] = LOAD(in + 128); + // s[2][1] = LOAD(in + 144); + // s[2][2] = LOAD(in + 160); + // s[2][3] = LOAD(in + 176); + // s[3][0] = LOAD(in + 192); + // s[3][1] = LOAD(in + 208); + // s[3][2] = LOAD(in + 224); + // s[3][3] = LOAD(in + 240); + // s[4][0] = LOAD(in + 256); + // s[4][1] = LOAD(in + 272); + // s[4][2] = LOAD(in + 288); + // s[4][3] = LOAD(in + 304); + // s[5][0] = LOAD(in + 320); + // s[5][1] = LOAD(in + 336); + // s[5][2] = LOAD(in + 352); + // s[5][3] = LOAD(in + 368); + // s[6][0] = LOAD(in + 384); + // s[6][1] = LOAD(in + 400); + // s[6][2] = LOAD(in + 416); + // s[6][3] = LOAD(in + 432); + // s[7][0] = LOAD(in + 448); + // s[7][1] = LOAD(in + 464); + // s[7][2] = LOAD(in + 480); + // s[7][3] = LOAD(in + 496); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 24); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 32); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // + // s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + // s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + // s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32)); + // s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48)); + // s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64)); + // s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80)); + // s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96)); + // s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112)); + // s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128)); + // s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144)); + // s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160)); + // s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176)); + // s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192)); + // s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208)); + // s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224)); + // s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240)); + // s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 256)); + // s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 272)); + // s[4][2] = _mm_xor_si128(s[4][2], LOAD(in + 288)); + // s[4][3] = _mm_xor_si128(s[4][3], LOAD(in + 304)); + // s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 320)); + // s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 336)); + // s[5][2] = _mm_xor_si128(s[5][2], LOAD(in + 352)); + // s[5][3] = _mm_xor_si128(s[5][3], LOAD(in + 368)); + // s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 384)); + // s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 400)); + // s[6][2] = _mm_xor_si128(s[6][2], LOAD(in + 416)); + // s[6][3] = _mm_xor_si128(s[6][3], LOAD(in + 432)); + // s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 448)); + // s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 464)); + // s[7][2] = _mm_xor_si128(s[7][2], LOAD(in + 480)); + // s[7][3] = _mm_xor_si128(s[7][3], LOAD(in + 496)); + // + // TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]); + // TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]); + // TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]); + // TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]); + // TRUNCSTORE(out + 128, s[4][0], s[4][1], s[4][2], s[4][3]); + // TRUNCSTORE(out + 160, s[5][0], s[5][1], s[5][2], s[5][3]); + // TRUNCSTORE(out + 192, s[6][0], s[6][1], s[6][2], s[6][3]); + // TRUNCSTORE(out + 224, s[7][0], s[7][1], s[7][2], s[7][3]); +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/haraka.h b/src/Native/libverushash/crypto/haraka.h new file mode 100644 index 000000000..91157fee6 --- /dev/null +++ b/src/Native/libverushash/crypto/haraka.h @@ -0,0 +1,128 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 kste + +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. + +Optimized Implementations for Haraka256 and Haraka512 +*/ +#ifndef HARAKA_H_ +#define HARAKA_H_ + +#include "immintrin.h" + +#define NUMROUNDS 5 + +#ifdef _WIN32 +typedef unsigned long long u64; +#else +typedef unsigned long u64; +#endif +typedef __m128i u128; + +extern u128 rc[40]; + +#define LOAD(src) _mm_load_si128((u128 *)(src)) +#define STORE(dest,src) _mm_storeu_si128((u128 *)(dest),src) + +#define AES2(s0, s1, rci) \ + s0 = _mm_aesenc_si128(s0, rc[rci]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \ + s0 = _mm_aesenc_si128(s0, rc[rci + 2]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 3]); + +#define AES2_4x(s0, s1, s2, s3, rci) \ + AES2(s0[0], s0[1], rci); \ + AES2(s1[0], s1[1], rci); \ + AES2(s2[0], s2[1], rci); \ + AES2(s3[0], s3[1], rci); + +#define AES2_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \ + AES2_4x(s0, s1, s2, s3, rci); \ + AES2_4x(s4, s5, s6, s7, rci); + +#define AES4(s0, s1, s2, s3, rci) \ + s0 = _mm_aesenc_si128(s0, rc[rci]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \ + s2 = _mm_aesenc_si128(s2, rc[rci + 2]); \ + s3 = _mm_aesenc_si128(s3, rc[rci + 3]); \ + s0 = _mm_aesenc_si128(s0, rc[rci + 4]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 5]); \ + s2 = _mm_aesenc_si128(s2, rc[rci + 6]); \ + s3 = _mm_aesenc_si128(s3, rc[rci + 7]); \ + +#define AES4_zero(s0, s1, s2, s3, rci) \ + s0 = _mm_aesenc_si128(s0, rc0[rci]); \ + s1 = _mm_aesenc_si128(s1, rc0[rci + 1]); \ + s2 = _mm_aesenc_si128(s2, rc0[rci + 2]); \ + s3 = _mm_aesenc_si128(s3, rc0[rci + 3]); \ + s0 = _mm_aesenc_si128(s0, rc0[rci + 4]); \ + s1 = _mm_aesenc_si128(s1, rc0[rci + 5]); \ + s2 = _mm_aesenc_si128(s2, rc0[rci + 6]); \ + s3 = _mm_aesenc_si128(s3, rc0[rci + 7]); \ + +#define AES4_4x(s0, s1, s2, s3, rci) \ + AES4(s0[0], s0[1], s0[2], s0[3], rci); \ + AES4(s1[0], s1[1], s1[2], s1[3], rci); \ + AES4(s2[0], s2[1], s2[2], s2[3], rci); \ + AES4(s3[0], s3[1], s3[2], s3[3], rci); + +#define AES4_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \ + AES4_4x(s0, s1, s2, s3, rci); \ + AES4_4x(s4, s5, s6, s7, rci); + +#define MIX2(s0, s1) \ + tmp = _mm_unpacklo_epi32(s0, s1); \ + s1 = _mm_unpackhi_epi32(s0, s1); \ + s0 = tmp; + +#define MIX4(s0, s1, s2, s3) \ + tmp = _mm_unpacklo_epi32(s0, s1); \ + s0 = _mm_unpackhi_epi32(s0, s1); \ + s1 = _mm_unpacklo_epi32(s2, s3); \ + s2 = _mm_unpackhi_epi32(s2, s3); \ + s3 = _mm_unpacklo_epi32(s0, s2); \ + s0 = _mm_unpackhi_epi32(s0, s2); \ + s2 = _mm_unpackhi_epi32(s1, tmp); \ + s1 = _mm_unpacklo_epi32(s1, tmp); + +#define TRUNCSTORE(out, s0, s1, s2, s3) \ + *(u64*)(out) = *(((u64*)&(s0) + 1)); \ + *(u64*)(out + 8) = *(((u64*)&(s1) + 1)); \ + *(u64*)(out + 16) = *(((u64*)&(s2) + 0)); \ + *(u64*)(out + 24) = *(((u64*)&(s3) + 0)); + +void load_constants(); +void test_implementations(); + +void load_constants(); + +void haraka256(unsigned char *out, const unsigned char *in); +void haraka256_keyed(unsigned char *out, const unsigned char *in, const u128 *rc); +void haraka256_4x(unsigned char *out, const unsigned char *in); +void haraka256_8x(unsigned char *out, const unsigned char *in); + +void haraka512(unsigned char *out, const unsigned char *in); +void haraka512_zero(unsigned char *out, const unsigned char *in); +void haraka512_keyed(unsigned char *out, const unsigned char *in, const u128 *rc); +void haraka512_4x(unsigned char *out, const unsigned char *in); +void haraka512_8x(unsigned char *out, const unsigned char *in); + +#endif \ No newline at end of file diff --git a/src/Native/libverushash/crypto/haraka_portable.c b/src/Native/libverushash/crypto/haraka_portable.c new file mode 100644 index 000000000..4b46ab468 --- /dev/null +++ b/src/Native/libverushash/crypto/haraka_portable.c @@ -0,0 +1,428 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka_portable.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc0[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = +{ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +void aesenc(unsigned char *s, const unsigned char *rk) +{ + unsigned char i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i%4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= u ^ XT(v[i][0] ^ v[i][1]); + v[i][1] ^= u ^ XT(v[i][1] ^ v[i][2]); + v[i][2] ^= u ^ XT(v[i][2] ^ v[i][3]); + v[i][3] ^= u ^ XT(v[i][3] ^ t); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) +{ + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) +{ + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void load_constants_port() +{ + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40*16); +} + +void tweak_constants(const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) +{ + unsigned char buf[40*16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40*16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + haraka_S(buf, 40*16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40*16); + } + + /* Constants for pk.seed */ + haraka_S(buf, 40*16, pk_seed, seed_length); + memcpy(rc, buf, 40*16); +} + +static void haraka_S_absorb(unsigned char *s, + const unsigned char *m, unsigned long long mlen, + unsigned char p) +{ + unsigned long long i; + unsigned char t[32]; + + while (mlen >= 32) { + // XOR block to state + for (i = 0; i < 32; ++i) { + s[i] ^= m[i]; + } + haraka512_perm(s, s); + mlen -= 32; + m += 32; + } + + for (i = 0; i < 32; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[32 - 1] |= 128; + for (i = 0; i < 32; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) +{ + while (nblocks > 0) { + haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + + +void haraka_S(unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) +{ + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void haraka512_perm(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4*2*i + 4*j]); + aesenc(s + 16, rc[4*2*i + 4*j + 1]); + aesenc(s + 32, rc[4*2*i + 4*j + 2]); + aesenc(s + 48, rc[4*2*i + 4*j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void haraka512_perm_keyed(unsigned char *out, const unsigned char *in, const u128 *rc) +{ + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, (const unsigned char *)&rc[4*2*i + 4*j]); + aesenc(s + 16, (const unsigned char *)&rc[4*2*i + 4*j + 1]); + aesenc(s + 32, (const unsigned char *)&rc[4*2*i + 4*j + 2]); + aesenc(s + 48, (const unsigned char *)&rc[4*2*i + 4*j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void haraka512_port(unsigned char *out, const unsigned char *in) +{ + int i; + + unsigned char buf[64]; + + haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + +void haraka512_port_keyed(unsigned char *out, const unsigned char *in, const u128 *rc) +{ + int i; + + unsigned char buf[64]; + + haraka512_perm_keyed(buf, in, rc); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + +void haraka512_perm_zero(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc0[4*2*i + 4*j]); + aesenc(s + 16, rc0[4*2*i + 4*j + 1]); + aesenc(s + 32, rc0[4*2*i + 4*j + 2]); + aesenc(s + 48, rc0[4*2*i + 4*j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void haraka512_port_zero(unsigned char *out, const unsigned char *in) +{ + int i; + + unsigned char buf[64]; + + haraka512_perm_zero(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + +void haraka256_port(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2*2*i + 2*j]); + aesenc(s + 16, rc[2*2*i + 2*j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void haraka256_sk(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2*2*i + 2*j]); + aesenc(s + 16, rc_sseed[2*2*i + 2*j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/haraka_portable.h b/src/Native/libverushash/crypto/haraka_portable.h new file mode 100644 index 000000000..219aba91f --- /dev/null +++ b/src/Native/libverushash/crypto/haraka_portable.h @@ -0,0 +1,84 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +#include "immintrin.h" + +#define NUMROUNDS 5 + +#ifdef _WIN32 +typedef unsigned long long u64; +#else +typedef unsigned long u64; +#endif +typedef __m128i u128; + +extern void aesenc(unsigned char *s, const unsigned char *rk); + +#define AES2_EMU(s0, s1, rci) \ + aesenc((unsigned char *)&s0, (unsigned char *)&(rc[rci])); \ + aesenc((unsigned char *)&s1, (unsigned char *)&(rc[rci + 1])); \ + aesenc((unsigned char *)&s0, (unsigned char *)&(rc[rci + 2])); \ + aesenc((unsigned char *)&s1, (unsigned char *)&(rc[rci + 3])); + +typedef unsigned int uint32_t; + +static inline __m128i _mm_unpacklo_epi32_emu(__m128i a, __m128i b) +{ + uint32_t result[4]; + uint32_t *tmp1 = (uint32_t *)&a, *tmp2 = (uint32_t *)&b; + result[0] = tmp1[0]; + result[1] = tmp2[0]; + result[2] = tmp1[1]; + result[3] = tmp2[1]; + return *(__m128i *)result; +} + +static inline __m128i _mm_unpackhi_epi32_emu(__m128i a, __m128i b) +{ + uint32_t result[4]; + uint32_t *tmp1 = (uint32_t *)&a, *tmp2 = (uint32_t *)&b; + result[0] = tmp1[2]; + result[1] = tmp2[2]; + result[2] = tmp1[3]; + result[3] = tmp2[3]; + return *(__m128i *)result; +} + +#define MIX2_EMU(s0, s1) \ + tmp = _mm_unpacklo_epi32_emu(s0, s1); \ + s1 = _mm_unpackhi_epi32_emu(s0, s1); \ + s0 = tmp; + +/* load constants */ +void load_constants_port(); + +/* Tweak constants with seed */ +void tweak_constants(const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void haraka_S(unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void haraka512_port(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void haraka512_port_keyed(unsigned char *out, const unsigned char *in, const u128 *rc); + +/* Applies the 512-bit Haraka permutation to in, using zero key. */ +void haraka512_perm_zero(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512, using zero key */ +void haraka512_port_zero(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void haraka256_port(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif \ No newline at end of file diff --git a/src/Native/libverushash/crypto/ripemd160.cpp b/src/Native/libverushash/crypto/ripemd160.cpp new file mode 100644 index 000000000..69d9339a5 --- /dev/null +++ b/src/Native/libverushash/crypto/ripemd160.cpp @@ -0,0 +1,291 @@ +// Copyright (c) 2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + +#include "ripemd160.h" +#include "common.h" + +#include + +// Internal implementation code. +namespace +{ +/// Internal RIPEMD-160 implementation. +namespace ripemd160 +{ +uint32_t inline f1(uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; } +uint32_t inline f2(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); } +uint32_t inline f3(uint32_t x, uint32_t y, uint32_t z) { return (x | ~y) ^ z; } +uint32_t inline f4(uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); } +uint32_t inline f5(uint32_t x, uint32_t y, uint32_t z) { return x ^ (y | ~z); } + +/** Initialize RIPEMD-160 state. */ +void inline Initialize(uint32_t* s) +{ + s[0] = 0x67452301ul; + s[1] = 0xEFCDAB89ul; + s[2] = 0x98BADCFEul; + s[3] = 0x10325476ul; + s[4] = 0xC3D2E1F0ul; +} + +uint32_t inline rol(uint32_t x, int i) { return (x << i) | (x >> (32 - i)); } + +void inline Round(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t f, uint32_t x, uint32_t k, int r) +{ + a = rol(a + f + x + k, r) + e; + c = rol(c, 10); +} + +void inline R11(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); } +void inline R21(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x5A827999ul, r); } +void inline R31(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6ED9EBA1ul, r); } +void inline R41(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x8F1BBCDCul, r); } +void inline R51(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0xA953FD4Eul, r); } + +void inline R12(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0x50A28BE6ul, r); } +void inline R22(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x5C4DD124ul, r); } +void inline R32(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6D703EF3ul, r); } +void inline R42(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x7A6D76E9ul, r); } +void inline R52(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); } + +/** Perform a RIPEMD-160 transformation, processing a 64-byte chunk. */ +void Transform(uint32_t* s, const unsigned char* chunk) +{ + uint32_t a1 = s[0], b1 = s[1], c1 = s[2], d1 = s[3], e1 = s[4]; + uint32_t a2 = a1, b2 = b1, c2 = c1, d2 = d1, e2 = e1; + uint32_t w0 = ReadLE32(chunk + 0), w1 = ReadLE32(chunk + 4), w2 = ReadLE32(chunk + 8), w3 = ReadLE32(chunk + 12); + uint32_t w4 = ReadLE32(chunk + 16), w5 = ReadLE32(chunk + 20), w6 = ReadLE32(chunk + 24), w7 = ReadLE32(chunk + 28); + uint32_t w8 = ReadLE32(chunk + 32), w9 = ReadLE32(chunk + 36), w10 = ReadLE32(chunk + 40), w11 = ReadLE32(chunk + 44); + uint32_t w12 = ReadLE32(chunk + 48), w13 = ReadLE32(chunk + 52), w14 = ReadLE32(chunk + 56), w15 = ReadLE32(chunk + 60); + + R11(a1, b1, c1, d1, e1, w0, 11); + R12(a2, b2, c2, d2, e2, w5, 8); + R11(e1, a1, b1, c1, d1, w1, 14); + R12(e2, a2, b2, c2, d2, w14, 9); + R11(d1, e1, a1, b1, c1, w2, 15); + R12(d2, e2, a2, b2, c2, w7, 9); + R11(c1, d1, e1, a1, b1, w3, 12); + R12(c2, d2, e2, a2, b2, w0, 11); + R11(b1, c1, d1, e1, a1, w4, 5); + R12(b2, c2, d2, e2, a2, w9, 13); + R11(a1, b1, c1, d1, e1, w5, 8); + R12(a2, b2, c2, d2, e2, w2, 15); + R11(e1, a1, b1, c1, d1, w6, 7); + R12(e2, a2, b2, c2, d2, w11, 15); + R11(d1, e1, a1, b1, c1, w7, 9); + R12(d2, e2, a2, b2, c2, w4, 5); + R11(c1, d1, e1, a1, b1, w8, 11); + R12(c2, d2, e2, a2, b2, w13, 7); + R11(b1, c1, d1, e1, a1, w9, 13); + R12(b2, c2, d2, e2, a2, w6, 7); + R11(a1, b1, c1, d1, e1, w10, 14); + R12(a2, b2, c2, d2, e2, w15, 8); + R11(e1, a1, b1, c1, d1, w11, 15); + R12(e2, a2, b2, c2, d2, w8, 11); + R11(d1, e1, a1, b1, c1, w12, 6); + R12(d2, e2, a2, b2, c2, w1, 14); + R11(c1, d1, e1, a1, b1, w13, 7); + R12(c2, d2, e2, a2, b2, w10, 14); + R11(b1, c1, d1, e1, a1, w14, 9); + R12(b2, c2, d2, e2, a2, w3, 12); + R11(a1, b1, c1, d1, e1, w15, 8); + R12(a2, b2, c2, d2, e2, w12, 6); + + R21(e1, a1, b1, c1, d1, w7, 7); + R22(e2, a2, b2, c2, d2, w6, 9); + R21(d1, e1, a1, b1, c1, w4, 6); + R22(d2, e2, a2, b2, c2, w11, 13); + R21(c1, d1, e1, a1, b1, w13, 8); + R22(c2, d2, e2, a2, b2, w3, 15); + R21(b1, c1, d1, e1, a1, w1, 13); + R22(b2, c2, d2, e2, a2, w7, 7); + R21(a1, b1, c1, d1, e1, w10, 11); + R22(a2, b2, c2, d2, e2, w0, 12); + R21(e1, a1, b1, c1, d1, w6, 9); + R22(e2, a2, b2, c2, d2, w13, 8); + R21(d1, e1, a1, b1, c1, w15, 7); + R22(d2, e2, a2, b2, c2, w5, 9); + R21(c1, d1, e1, a1, b1, w3, 15); + R22(c2, d2, e2, a2, b2, w10, 11); + R21(b1, c1, d1, e1, a1, w12, 7); + R22(b2, c2, d2, e2, a2, w14, 7); + R21(a1, b1, c1, d1, e1, w0, 12); + R22(a2, b2, c2, d2, e2, w15, 7); + R21(e1, a1, b1, c1, d1, w9, 15); + R22(e2, a2, b2, c2, d2, w8, 12); + R21(d1, e1, a1, b1, c1, w5, 9); + R22(d2, e2, a2, b2, c2, w12, 7); + R21(c1, d1, e1, a1, b1, w2, 11); + R22(c2, d2, e2, a2, b2, w4, 6); + R21(b1, c1, d1, e1, a1, w14, 7); + R22(b2, c2, d2, e2, a2, w9, 15); + R21(a1, b1, c1, d1, e1, w11, 13); + R22(a2, b2, c2, d2, e2, w1, 13); + R21(e1, a1, b1, c1, d1, w8, 12); + R22(e2, a2, b2, c2, d2, w2, 11); + + R31(d1, e1, a1, b1, c1, w3, 11); + R32(d2, e2, a2, b2, c2, w15, 9); + R31(c1, d1, e1, a1, b1, w10, 13); + R32(c2, d2, e2, a2, b2, w5, 7); + R31(b1, c1, d1, e1, a1, w14, 6); + R32(b2, c2, d2, e2, a2, w1, 15); + R31(a1, b1, c1, d1, e1, w4, 7); + R32(a2, b2, c2, d2, e2, w3, 11); + R31(e1, a1, b1, c1, d1, w9, 14); + R32(e2, a2, b2, c2, d2, w7, 8); + R31(d1, e1, a1, b1, c1, w15, 9); + R32(d2, e2, a2, b2, c2, w14, 6); + R31(c1, d1, e1, a1, b1, w8, 13); + R32(c2, d2, e2, a2, b2, w6, 6); + R31(b1, c1, d1, e1, a1, w1, 15); + R32(b2, c2, d2, e2, a2, w9, 14); + R31(a1, b1, c1, d1, e1, w2, 14); + R32(a2, b2, c2, d2, e2, w11, 12); + R31(e1, a1, b1, c1, d1, w7, 8); + R32(e2, a2, b2, c2, d2, w8, 13); + R31(d1, e1, a1, b1, c1, w0, 13); + R32(d2, e2, a2, b2, c2, w12, 5); + R31(c1, d1, e1, a1, b1, w6, 6); + R32(c2, d2, e2, a2, b2, w2, 14); + R31(b1, c1, d1, e1, a1, w13, 5); + R32(b2, c2, d2, e2, a2, w10, 13); + R31(a1, b1, c1, d1, e1, w11, 12); + R32(a2, b2, c2, d2, e2, w0, 13); + R31(e1, a1, b1, c1, d1, w5, 7); + R32(e2, a2, b2, c2, d2, w4, 7); + R31(d1, e1, a1, b1, c1, w12, 5); + R32(d2, e2, a2, b2, c2, w13, 5); + + R41(c1, d1, e1, a1, b1, w1, 11); + R42(c2, d2, e2, a2, b2, w8, 15); + R41(b1, c1, d1, e1, a1, w9, 12); + R42(b2, c2, d2, e2, a2, w6, 5); + R41(a1, b1, c1, d1, e1, w11, 14); + R42(a2, b2, c2, d2, e2, w4, 8); + R41(e1, a1, b1, c1, d1, w10, 15); + R42(e2, a2, b2, c2, d2, w1, 11); + R41(d1, e1, a1, b1, c1, w0, 14); + R42(d2, e2, a2, b2, c2, w3, 14); + R41(c1, d1, e1, a1, b1, w8, 15); + R42(c2, d2, e2, a2, b2, w11, 14); + R41(b1, c1, d1, e1, a1, w12, 9); + R42(b2, c2, d2, e2, a2, w15, 6); + R41(a1, b1, c1, d1, e1, w4, 8); + R42(a2, b2, c2, d2, e2, w0, 14); + R41(e1, a1, b1, c1, d1, w13, 9); + R42(e2, a2, b2, c2, d2, w5, 6); + R41(d1, e1, a1, b1, c1, w3, 14); + R42(d2, e2, a2, b2, c2, w12, 9); + R41(c1, d1, e1, a1, b1, w7, 5); + R42(c2, d2, e2, a2, b2, w2, 12); + R41(b1, c1, d1, e1, a1, w15, 6); + R42(b2, c2, d2, e2, a2, w13, 9); + R41(a1, b1, c1, d1, e1, w14, 8); + R42(a2, b2, c2, d2, e2, w9, 12); + R41(e1, a1, b1, c1, d1, w5, 6); + R42(e2, a2, b2, c2, d2, w7, 5); + R41(d1, e1, a1, b1, c1, w6, 5); + R42(d2, e2, a2, b2, c2, w10, 15); + R41(c1, d1, e1, a1, b1, w2, 12); + R42(c2, d2, e2, a2, b2, w14, 8); + + R51(b1, c1, d1, e1, a1, w4, 9); + R52(b2, c2, d2, e2, a2, w12, 8); + R51(a1, b1, c1, d1, e1, w0, 15); + R52(a2, b2, c2, d2, e2, w15, 5); + R51(e1, a1, b1, c1, d1, w5, 5); + R52(e2, a2, b2, c2, d2, w10, 12); + R51(d1, e1, a1, b1, c1, w9, 11); + R52(d2, e2, a2, b2, c2, w4, 9); + R51(c1, d1, e1, a1, b1, w7, 6); + R52(c2, d2, e2, a2, b2, w1, 12); + R51(b1, c1, d1, e1, a1, w12, 8); + R52(b2, c2, d2, e2, a2, w5, 5); + R51(a1, b1, c1, d1, e1, w2, 13); + R52(a2, b2, c2, d2, e2, w8, 14); + R51(e1, a1, b1, c1, d1, w10, 12); + R52(e2, a2, b2, c2, d2, w7, 6); + R51(d1, e1, a1, b1, c1, w14, 5); + R52(d2, e2, a2, b2, c2, w6, 8); + R51(c1, d1, e1, a1, b1, w1, 12); + R52(c2, d2, e2, a2, b2, w2, 13); + R51(b1, c1, d1, e1, a1, w3, 13); + R52(b2, c2, d2, e2, a2, w13, 6); + R51(a1, b1, c1, d1, e1, w8, 14); + R52(a2, b2, c2, d2, e2, w14, 5); + R51(e1, a1, b1, c1, d1, w11, 11); + R52(e2, a2, b2, c2, d2, w0, 15); + R51(d1, e1, a1, b1, c1, w6, 8); + R52(d2, e2, a2, b2, c2, w3, 13); + R51(c1, d1, e1, a1, b1, w15, 5); + R52(c2, d2, e2, a2, b2, w9, 11); + R51(b1, c1, d1, e1, a1, w13, 6); + R52(b2, c2, d2, e2, a2, w11, 11); + + uint32_t t = s[0]; + s[0] = s[1] + c1 + d2; + s[1] = s[2] + d1 + e2; + s[2] = s[3] + e1 + a2; + s[3] = s[4] + a1 + b2; + s[4] = t + b1 + c2; +} + +} // namespace ripemd160 + +} // namespace + +////// RIPEMD160 + +CRIPEMD160::CRIPEMD160() : bytes(0) +{ + ripemd160::Initialize(s); +} + +CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len) +{ + const unsigned char* end = data + len; + size_t bufsize = bytes % 64; + if (bufsize && bufsize + len >= 64) { + // Fill the buffer, and process it. + memcpy(buf + bufsize, data, 64 - bufsize); + bytes += 64 - bufsize; + data += 64 - bufsize; + ripemd160::Transform(s, buf); + bufsize = 0; + } + while (end >= data + 64) { + // Process full chunks directly from the source. + ripemd160::Transform(s, data); + bytes += 64; + data += 64; + } + if (end > data) { + // Fill the buffer with what remains. + memcpy(buf + bufsize, data, end - data); + bytes += end - data; + } + return *this; +} + +void CRIPEMD160::Finalize(unsigned char hash[OUTPUT_SIZE]) +{ + static const unsigned char pad[64] = {0x80}; + unsigned char sizedesc[8]; + WriteLE64(sizedesc, bytes << 3); + Write(pad, 1 + ((119 - (bytes % 64)) % 64)); + Write(sizedesc, 8); + WriteLE32(hash, s[0]); + WriteLE32(hash + 4, s[1]); + WriteLE32(hash + 8, s[2]); + WriteLE32(hash + 12, s[3]); + WriteLE32(hash + 16, s[4]); +} + +CRIPEMD160& CRIPEMD160::Reset() +{ + bytes = 0; + ripemd160::Initialize(s); + return *this; +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/ripemd160.h b/src/Native/libverushash/crypto/ripemd160.h new file mode 100644 index 000000000..9815b4ab1 --- /dev/null +++ b/src/Native/libverushash/crypto/ripemd160.h @@ -0,0 +1,28 @@ +// Copyright (c) 2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + +#ifndef BITCOIN_CRYPTO_RIPEMD160_H +#define BITCOIN_CRYPTO_RIPEMD160_H + +#include +#include + +/** A hasher class for RIPEMD-160. */ +class CRIPEMD160 +{ +private: + uint32_t s[5]; + unsigned char buf[64]; + size_t bytes; + +public: + static const size_t OUTPUT_SIZE = 20; + + CRIPEMD160(); + CRIPEMD160& Write(const unsigned char* data, size_t len); + void Finalize(unsigned char hash[OUTPUT_SIZE]); + CRIPEMD160& Reset(); +}; + +#endif // BITCOIN_CRYPTO_RIPEMD160_H \ No newline at end of file diff --git a/src/Native/libverushash/crypto/sha256.cpp b/src/Native/libverushash/crypto/sha256.cpp new file mode 100644 index 000000000..afa282df1 --- /dev/null +++ b/src/Native/libverushash/crypto/sha256.cpp @@ -0,0 +1,199 @@ +// Copyright (c) 2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + +#include "sha256.h" + +#include "common.h" + +#include +#include + +// Internal implementation code. +namespace +{ +/// Internal SHA-256 implementation. +namespace sha256 +{ +uint32_t inline Ch(uint32_t x, uint32_t y, uint32_t z) { return z ^ (x & (y ^ z)); } +uint32_t inline Maj(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (z & (x | y)); } +uint32_t inline Sigma0(uint32_t x) { return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10); } +uint32_t inline Sigma1(uint32_t x) { return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7); } +uint32_t inline sigma0(uint32_t x) { return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3); } +uint32_t inline sigma1(uint32_t x) { return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10); } + +/** One round of SHA-256. */ +void inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t& d, uint32_t e, uint32_t f, uint32_t g, uint32_t& h, uint32_t k, uint32_t w) +{ + uint32_t t1 = h + Sigma1(e) + Ch(e, f, g) + k + w; + uint32_t t2 = Sigma0(a) + Maj(a, b, c); + d += t1; + h = t1 + t2; +} + +/** Initialize SHA-256 state. */ +void inline Initialize(uint32_t* s) +{ + s[0] = 0x6a09e667ul; + s[1] = 0xbb67ae85ul; + s[2] = 0x3c6ef372ul; + s[3] = 0xa54ff53aul; + s[4] = 0x510e527ful; + s[5] = 0x9b05688cul; + s[6] = 0x1f83d9abul; + s[7] = 0x5be0cd19ul; +} + +/** Perform one SHA-256 transformation, processing a 64-byte chunk. */ +void Transform(uint32_t* s, const unsigned char* chunk) +{ + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0)); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4)); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8)); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12)); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16)); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20)); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24)); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28)); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32)); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36)); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = ReadBE32(chunk + 40)); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = ReadBE32(chunk + 44)); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = ReadBE32(chunk + 48)); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = ReadBE32(chunk + 52)); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = ReadBE32(chunk + 56)); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = ReadBE32(chunk + 60)); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +} // namespace sha256 +} // namespace + + +////// SHA-256 + +CSHA256::CSHA256() : bytes(0) +{ + sha256::Initialize(s); +} + +CSHA256& CSHA256::Write(const unsigned char* data, size_t len) +{ + const unsigned char* end = data + len; + size_t bufsize = bytes % 64; + if (bufsize && bufsize + len >= 64) { + // Fill the buffer, and process it. + memcpy(buf + bufsize, data, 64 - bufsize); + bytes += 64 - bufsize; + data += 64 - bufsize; + sha256::Transform(s, buf); + bufsize = 0; + } + while (end >= data + 64) { + // Process full chunks directly from the source. + sha256::Transform(s, data); + bytes += 64; + data += 64; + } + if (end > data) { + // Fill the buffer with what remains. + memcpy(buf + bufsize, data, end - data); + bytes += end - data; + } + return *this; +} + +void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE]) +{ + static const unsigned char pad[64] = {0x80}; + unsigned char sizedesc[8]; + WriteBE64(sizedesc, bytes << 3); + Write(pad, 1 + ((119 - (bytes % 64)) % 64)); + Write(sizedesc, 8); + FinalizeNoPadding(hash, false); +} + +void CSHA256::FinalizeNoPadding(unsigned char hash[OUTPUT_SIZE], bool enforce_compression) +{ + if (enforce_compression && bytes != 64) { + throw std::length_error("SHA256Compress should be invoked with a 512-bit block"); + } + + WriteBE32(hash, s[0]); + WriteBE32(hash + 4, s[1]); + WriteBE32(hash + 8, s[2]); + WriteBE32(hash + 12, s[3]); + WriteBE32(hash + 16, s[4]); + WriteBE32(hash + 20, s[5]); + WriteBE32(hash + 24, s[6]); + WriteBE32(hash + 28, s[7]); +} + +CSHA256& CSHA256::Reset() +{ + bytes = 0; + sha256::Initialize(s); + return *this; +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/sha256.h b/src/Native/libverushash/crypto/sha256.h new file mode 100644 index 000000000..c6d6467da --- /dev/null +++ b/src/Native/libverushash/crypto/sha256.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://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/libverushash/crypto/tinyformat.h b/src/Native/libverushash/crypto/tinyformat.h new file mode 100644 index 000000000..83afac544 --- /dev/null +++ b/src/Native/libverushash/crypto/tinyformat.h @@ -0,0 +1,1013 @@ +// 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. +// +// +// 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. +// +// +// 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 + +#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 + +#ifdef __GNUC__ +# define TINYFORMAT_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) +# define TINYFORMAT_NOINLINE __declspec(noinline) +#else +# define TINYFORMAT_NOINLINE +#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 + +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); } +}; + +} // namespace detail + + +//------------------------------------------------------------------------------ +// Variable formatting functions. May be overridden for user-defined types if +// desired. + + +// Format a value into a stream. Called from format() for all types 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). +// +// 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, 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 + 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, 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 { + +// Class holding current position in format string and an output stream into +// which arguments are formatted. +class FormatIterator +{ + public: + // Flags for features not representable with standard stream state + enum ExtraFormatFlags + { + Flag_None = 0, + Flag_TruncateToPrecision = 1<<0, // truncate length to stream precision() + Flag_SpacePadPositive = 1<<1, // pad positive values with spaces + Flag_VariableWidth = 1<<2, // variable field width in arg list + Flag_VariablePrecision = 1<<3 // variable field precision in arg list + }; + + // out is the output stream, fmt is the full format string + FormatIterator(std::ostream& out, const char* fmt) + : m_out(out), + m_fmt(fmt), + m_extraFlags(Flag_None), + m_wantWidth(false), + m_wantPrecision(false), + m_variableWidth(0), + m_variablePrecision(0), + m_origWidth(out.width()), + m_origPrecision(out.precision()), + m_origFlags(out.flags()), + m_origFill(out.fill()) + { } + + // Print remaining part of format string. + void finish() + { + // It would be nice if we could do this from the destructor, but we + // can't if TINFORMAT_ERROR is used to throw an exception! + m_fmt = printFormatStringLiteral(m_out, m_fmt); + if(*m_fmt != '\0') + TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string"); + } + + ~FormatIterator() + { + // Restore stream state + m_out.width(m_origWidth); + m_out.precision(m_origPrecision); + m_out.flags(m_origFlags); + m_out.fill(m_origFill); + } + + template + void accept(const T& value); + + private: + // Parse and return an integer from the string c, as atoi() + // On return, c is set to one past the end of the integer. + static int parseIntAndAdvance(const char*& c) + { + int i = 0; + for(;*c >= '0' && *c <= '9'; ++c) + i = 10*i + (*c - '0'); + return i; + } + + // Format at most truncLen characters of a C string to the given + // stream. Return true if formatting proceeded (generic version always + // returns false) + template + static bool formatCStringTruncate(std::ostream& /*out*/, const T& /*value*/, + std::streamsize /*truncLen*/) + { + return false; + } +# define TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(type) \ + static bool formatCStringTruncate(std::ostream& out, type* value, \ + std::streamsize truncLen) \ + { \ + std::streamsize len = 0; \ + while(len < truncLen && value[len] != 0) \ + ++len; \ + out.write(value, len); \ + return true; \ + } + // Overload for const char* and char*. Could overload for signed & + // unsigned char too, but these are technically unneeded for printf + // compatibility. + TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(const char) + TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE(char) +# undef TINYFORMAT_DEFINE_FORMAT_C_STRING_TRUNCATE + + // 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. + static const char* printFormatStringLiteral(std::ostream& out, + const char* fmt) + { + const char* c = fmt; + for(; true; ++c) + { + switch(*c) + { + case '\0': + out.write(fmt, static_cast(c - fmt)); + return c; + case '%': + out.write(fmt, static_cast(c - fmt)); + if(*(c+1) != '%') + return c; + // for "%%", tack trailing % onto next literal section. + fmt = ++c; + break; + } + } + } + + static const char* streamStateFromFormat(std::ostream& out, + unsigned int& extraFlags, + const char* fmtStart, + int variableWidth, + int variablePrecision); + + // Private copy & assign: Kill gcc warnings with -Weffc++ + FormatIterator(const FormatIterator&); + FormatIterator& operator=(const FormatIterator&); + + // Stream, current format string & state + std::ostream& m_out; + const char* m_fmt; + unsigned int m_extraFlags; + // State machine info for handling of variable width & precision + bool m_wantWidth; + bool m_wantPrecision; + int m_variableWidth; + int m_variablePrecision; + // Saved stream state + std::streamsize m_origWidth; + std::streamsize m_origPrecision; + std::ios::fmtflags m_origFlags; + char m_origFill; +}; + + +// Accept a value for formatting into the internal stream. +template +TINYFORMAT_NOINLINE // < greatly reduces bloat in optimized builds +void FormatIterator::accept(const T& value) +{ + // Parse the format string + const char* fmtEnd = 0; + if(m_extraFlags == Flag_None && !m_wantWidth && !m_wantPrecision) + { + m_fmt = printFormatStringLiteral(m_out, m_fmt); + fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt, 0, 0); + m_wantWidth = (m_extraFlags & Flag_VariableWidth) != 0; + m_wantPrecision = (m_extraFlags & Flag_VariablePrecision) != 0; + } + // Consume value as variable width and precision specifier if necessary + if(m_extraFlags & (Flag_VariableWidth | Flag_VariablePrecision)) + { + if(m_wantWidth || m_wantPrecision) + { + int v = convertToInt::invoke(value); + if(m_wantWidth) + { + m_variableWidth = v; + m_wantWidth = false; + } + else if(m_wantPrecision) + { + m_variablePrecision = v; + m_wantPrecision = false; + } + return; + } + // If we get here, we've set both the variable precision and width as + // required and we need to rerun the stream state setup to insert these. + fmtEnd = streamStateFromFormat(m_out, m_extraFlags, m_fmt, + m_variableWidth, m_variablePrecision); + } + + // Format the value into the stream. + if(!(m_extraFlags & (Flag_SpacePadPositive | Flag_TruncateToPrecision))) + formatValue(m_out, m_fmt, fmtEnd, value); + else + { + // The following are special cases where there's no direct + // correspondence between stream formatting and the printf() behaviour. + // Instead, we simulate the behaviour crudely by formatting into a + // temporary string stream and munging the resulting string. + std::ostringstream tmpStream; + tmpStream.copyfmt(m_out); + if(m_extraFlags & Flag_SpacePadPositive) + tmpStream.setf(std::ios::showpos); + // formatCStringTruncate is required for truncating conversions like + // "%.4s" where at most 4 characters of the c-string should be read. + // If we didn't include this special case, we might read off the end. + if(!( (m_extraFlags & Flag_TruncateToPrecision) && + formatCStringTruncate(tmpStream, value, m_out.precision()) )) + { + // Not a truncated c-string; just format normally. + formatValue(tmpStream, m_fmt, fmtEnd, value); + } + std::string result = tmpStream.str(); // allocates... yuck. + if(m_extraFlags & Flag_SpacePadPositive) + { + for(size_t i = 0, iend = result.size(); i < iend; ++i) + if(result[i] == '+') + result[i] = ' '; + } + if((m_extraFlags & Flag_TruncateToPrecision) && + (int)result.size() > (int)m_out.precision()) + m_out.write(result.c_str(), m_out.precision()); + else + m_out << result; + } + m_extraFlags = Flag_None; + m_fmt = fmtEnd; +} + + +// 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 the extraFlags parameter which is a bitwise +// combination of values from the ExtraFormatFlags enum. +inline const char* FormatIterator::streamStateFromFormat(std::ostream& out, + unsigned int& extraFlags, + const char* fmtStart, + int variableWidth, + int variablePrecision) +{ + 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); + extraFlags = Flag_None; + bool precisionSet = false; + bool widthSet = false; + 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)) + extraFlags |= Flag_SpacePadPositive; + continue; + case '+': + out.setf(std::ios::showpos); + extraFlags &= ~Flag_SpacePadPositive; + continue; + } + break; + } + // 2) Parse width + if(*c >= '0' && *c <= '9') + { + widthSet = true; + out.width(parseIntAndAdvance(c)); + } + if(*c == '*') + { + widthSet = true; + if(variableWidth < 0) + { + // negative widths correspond to '-' flag set + out.fill(' '); + out.setf(std::ios::left, std::ios::adjustfield); + variableWidth = -variableWidth; + } + out.width(variableWidth); + extraFlags |= Flag_VariableWidth; + ++c; + } + // 3) Parse precision + if(*c == '.') + { + ++c; + int precision = 0; + if(*c == '*') + { + ++c; + extraFlags |= Flag_VariablePrecision; + precision = variablePrecision; + } + 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) + extraFlags |= Flag_TruncateToPrecision; + // 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; + } + 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()); + out.setf(std::ios::internal, std::ios::adjustfield); + out.fill('0'); + } + return c+1; +} + + + +//------------------------------------------------------------------------------ +// Private format function on top of which the public interface is implemented. +// We enforce a mimimum of one value to be formatted to prevent bugs looking like +// +// const char* myStr = "100% broken"; +// printf(myStr); // Parses % as a format specifier +#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES + +template +void format(FormatIterator& fmtIter, const T1& value1) +{ + fmtIter.accept(value1); + fmtIter.finish(); +} + +// General version for C++11 +template +void format(FormatIterator& fmtIter, const T1& value1, const Args&... args) +{ + fmtIter.accept(value1); + format(fmtIter, args...); +} + +#else + +inline void format(FormatIterator& fmtIter) +{ + fmtIter.finish(); +} + +// General version for C++98 +#define TINYFORMAT_MAKE_FORMAT_DETAIL(n) \ +template \ +void format(detail::FormatIterator& fmtIter, TINYFORMAT_VARARGS(n)) \ +{ \ + fmtIter.accept(v1); \ + format(fmtIter TINYFORMAT_PASSARGS_TAIL(n)); \ +} + +TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_DETAIL) +#undef TINYFORMAT_MAKE_FORMAT_DETAIL + +#endif // End C++98 variadic template emulation for format() + +} // namespace detail + + +//------------------------------------------------------------------------------ +// Implement all the main interface functions here in terms of detail::format() + +#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES + +// C++11 - the simple case +template +void format(std::ostream& out, const char* fmt, const T1& v1, const Args&... args) +{ + detail::FormatIterator fmtIter(out, fmt); + format(fmtIter, v1, args...); +} + +template +std::string format(const char* fmt, const T1& v1, const Args&... args) +{ + std::ostringstream oss; + format(oss, fmt, v1, args...); + return oss.str(); +} + +template +std::string format(const std::string &fmt, const T1& v1, const Args&... args) +{ + std::ostringstream oss; + format(oss, fmt.c_str(), v1, args...); + return oss.str(); +} + +template +void printf(const char* fmt, const T1& v1, const Args&... args) +{ + format(std::cout, fmt, v1, args...); +} + +#else + +// C++98 - define the interface functions using the wrapping macros +#define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \ + \ +template \ +void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + tinyformat::detail::FormatIterator fmtIter(out, fmt); \ + tinyformat::detail::format(fmtIter, TINYFORMAT_PASSARGS(n)); \ +} \ + \ +template \ +std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + std::ostringstream oss; \ + tinyformat::format(oss, fmt, TINYFORMAT_PASSARGS(n)); \ + return oss.str(); \ +} \ + \ +template \ +std::string format(const std::string &fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + std::ostringstream oss; \ + tinyformat::format(oss, fmt.c_str(), TINYFORMAT_PASSARGS(n)); \ + return oss.str(); \ +} \ + \ +template \ +void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \ +{ \ + tinyformat::format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ +} + +TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS) +#undef TINYFORMAT_MAKE_FORMAT_FUNCS +#endif + + +//------------------------------------------------------------------------------ +// Define deprecated wrapping macro for backward compatibility in tinyformat +// 1.x. Will be removed in version 2! +#define TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS +#define TINYFORMAT_WRAP_FORMAT_N(n, returnType, funcName, funcDeclSuffix, \ + bodyPrefix, streamName, bodySuffix) \ +template \ +returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt, \ + TINYFORMAT_VARARGS(n)) funcDeclSuffix \ +{ \ + bodyPrefix \ + tinyformat::format(streamName, fmt, TINYFORMAT_PASSARGS(n)); \ + bodySuffix \ +} \ + +#define TINYFORMAT_WRAP_FORMAT(returnType, funcName, funcDeclSuffix, \ + bodyPrefix, streamName, bodySuffix) \ +inline \ +returnType funcName(TINYFORMAT_WRAP_FORMAT_EXTRA_ARGS const char* fmt \ + ) funcDeclSuffix \ +{ \ + bodyPrefix \ + tinyformat::detail::FormatIterator(streamName, fmt).finish(); \ + bodySuffix \ +} \ +TINYFORMAT_WRAP_FORMAT_N(1 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(2 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(3 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(4 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(5 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(6 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(7 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(8 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(9 , returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(10, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(11, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(12, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(13, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(14, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(15, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ +TINYFORMAT_WRAP_FORMAT_N(16, returnType, funcName, funcDeclSuffix, bodyPrefix, streamName, bodySuffix) \ + + +} // namespace tinyformat + +#define strprintf tfm::format + +#endif // TINYFORMAT_H_INCLUDED \ No newline at end of file diff --git a/src/Native/libverushash/crypto/uint256.cpp b/src/Native/libverushash/crypto/uint256.cpp new file mode 100644 index 000000000..61570d1ec --- /dev/null +++ b/src/Native/libverushash/crypto/uint256.cpp @@ -0,0 +1,146 @@ +// 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); +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/uint256.h b/src/Native/libverushash/crypto/uint256.h new file mode 100644 index 000000000..cb12e7259 --- /dev/null +++ b/src/Native/libverushash/crypto/uint256.h @@ -0,0 +1,176 @@ +// 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 + +#ifdef _MSC_VER +# define _ALIGN(x) __declspec(align(x)) +#else +# define _ALIGN(x) __attribute__ ((aligned(x))) +#endif + +/** Template base class for fixed-sized opaque blobs. */ +template +class base_blob +{ +protected: + enum { WIDTH=BITS/8 }; + uint8_t _ALIGN(4) 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) const + { + s.write((char*)data, sizeof(data)); + } + + template + void Unserialize(Stream& s) + { + s.read((char*)data, 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 \ No newline at end of file diff --git a/src/Native/libverushash/crypto/utilstrencodings.cpp b/src/Native/libverushash/crypto/utilstrencodings.cpp new file mode 100644 index 000000000..d5289a17a --- /dev/null +++ b/src/Native/libverushash/crypto/utilstrencodings.cpp @@ -0,0 +1,500 @@ +// 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; +} + +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()); +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + char *endp = NULL; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int)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(); +} + +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 +#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 SanitizeString(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); + +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; +} + +#endif // BITCOIN_UTILSTRENCODINGS_H \ No newline at end of file diff --git a/src/Native/libverushash/crypto/verus_clhash.cpp b/src/Native/libverushash/crypto/verus_clhash.cpp new file mode 100644 index 000000000..5dd4e069f --- /dev/null +++ b/src/Native/libverushash/crypto/verus_clhash.cpp @@ -0,0 +1,1068 @@ +/* + * This uses veriations of the clhash algorithm for Verus Coin, licensed + * with the Apache-2.0 open source license. + * + * Copyright (c) 2018 Michael Toutonghi + * Distributed under the Apache 2.0 software license, available in the original form for clhash + * here: https://github.com/lemire/clhash/commit/934da700a2a54d8202929a826e2763831bd43cf7#diff-9879d6db96fd29134fc802214163b95a + * + * Original CLHash code and any portions herein, (C) 2017, 2018 Daniel Lemire and Owen Kaser + * Faster 64-bit universal hashing + * using carry-less multiplications, Journal of Cryptographic Engineering (to appear) + * + * Best used on recent x64 processors (Haswell or better). + * + * This implements an intermediate step in the last part of a Verus block hash. The intent of this step + * is to more effectively equalize FPGAs over GPUs and CPUs. + * + **/ + +#include "verus_hash.h" + +#include +#include + +#ifdef _WIN32 +#pragma warning (disable : 4146) +#include +#endif +int __cpuverusoptimized = 0x80; + +#if defined(__arm__) || defined(__aarch64__) +#include "crypto/SSE2NEON.h" +#else +#include +#endif + +#ifdef _WIN32 +#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno) +#endif + +thread_local thread_specific_ptr verusclhasher_key; +thread_local thread_specific_ptr verusclhasher_descr; + +#if defined(__APPLE__) || defined(_WIN32) +// attempt to workaround horrible mingw/gcc destructor bug on Windows and Mac, which passes garbage in the this pointer +// we use the opportunity of control here to clean up all of our tls variables. we could keep a list, but this is a safe, +// functional hack +thread_specific_ptr::~thread_specific_ptr() { + if (verusclhasher_key.ptr) + { + verusclhasher_key.reset(); + } + if (verusclhasher_descr.ptr) + { + verusclhasher_descr.reset(); + } +} +#endif // defined(__APPLE__) || defined(_WIN32) +#if defined(__arm__) || defined(__aarch64__) //intrinsics not defined in SSE2NEON.h + +static inline __attribute__((always_inline)) __m128i _mm_set_epi64x(uint64_t hi, uint64_t lo) + { + __m128i result; + ((uint64_t *)&result)[0] = lo; + ((uint64_t *)&result)[1] = hi; + return result; + } + +static inline __attribute__((always_inline)) __m128i _mm_mulhrs_epi16(__m128i _a, __m128i _b) +{ + int16_t result[8]; + int16_t *a = (int16_t*)&_a, *b = (int16_t*)&_b; + for (int i = 0; i < 8; i++) + { + result[i] = (int16_t)((((int32_t)(a[i]) * (int32_t)(b[i])) + 0x4000) >> 15); + } + + return *(__m128i *)result; +} + +__m128i _mm_cvtsi64_si128(uint64_t lo) +{ + __m128i result; + ((uint64_t *)&result)[0] = lo; + ((uint64_t *)&result)[1] = 0; + return result; +} + + static inline __attribute__((always_inline)) uint8x16_t _mm_aesenc_si128 (uint8x16_t a, uint8x16_t RoundKey) +{ + return vaesmcq_u8(vaeseq_u8(a, (uint8x16_t){})) ^ RoundKey; +} + + + static inline __attribute__((always_inline)) __m128i _mm_clmulepi64_si128(const __m128i a, const __m128i &b, int imm) +{ + return (__m128i)vmull_p64(vgetq_lane_u64(a, 1), vgetq_lane_u64(b,0)); + +} + +__m128i _mm_setr_epi8(u_char c0, u_char c1, u_char c2, u_char c3, u_char c4, u_char c5, u_char c6, u_char c7, u_char c8, u_char c9, u_char c10, u_char c11, u_char c12, u_char c13, u_char c14, u_char c15) +{ + __m128i result; + ((uint8_t *)&result)[0] = c0; + ((uint8_t *)&result)[1] = c1; + ((uint8_t *)&result)[2] = c2; + ((uint8_t *)&result)[3] = c3; + ((uint8_t *)&result)[4] = c4; + ((uint8_t *)&result)[5] = c5; + ((uint8_t *)&result)[6] = c6; + ((uint8_t *)&result)[7] = c7; + ((uint8_t *)&result)[8] = c8; + ((uint8_t *)&result)[9] = c9; + ((uint8_t *)&result)[10] = c10; + ((uint8_t *)&result)[11] = c11; + ((uint8_t *)&result)[12] = c12; + ((uint8_t *)&result)[13] = c13; + ((uint8_t *)&result)[14] = c14; + ((uint8_t *)&result)[15] = c15; + return result; +} +__m128i _mm_shuffle_epi8(__m128i a, __m128i b) +{ + __m128i result; + for (int i = 0; i < 16; i++) + { + if (((uint8_t *)&b)[i] & 0x80) + { + ((uint8_t *)&result)[i] = 0; + } + else + { + ((uint8_t *)&result)[i] = ((uint8_t *)&a)[((uint8_t *)&b)[i] & 0xf]; + } + } + return result; +} + int64_t _mm_cvtsi128_si64(__m128i a) +{ + return ((int64_t *)&a)[0]; +} +__m128i _mm_loadl_epi64(__m128i *a) +{ + __m128i b = {0}; ((uint64_t*)&b)[0] = ((uint64_t*)a)[0]; + return b; +} +#endif + +// multiply the length and the some key, no modulo + static inline __attribute__((always_inline)) __m128i lazyLengthHash(uint64_t keylength, uint64_t length) { + + const __m128i lengthvector = _mm_set_epi64x(keylength,length); + const __m128i clprod1 = _mm_clmulepi64_si128( lengthvector, lengthvector, 0x10); + return clprod1; +} + +// modulo reduction to 64-bit value. The high 64 bits contain garbage, see precompReduction64 + static inline __attribute__((always_inline)) __m128i precompReduction64_si128( __m128i A) { + //const __m128i C = _mm_set_epi64x(1U,(1U<<4)+(1U<<3)+(1U<<1)+(1U<<0)); // C is the irreducible poly. (64,4,3,1,0) + const __m128i C = _mm_cvtsi64_si128((1U<<4)+(1U<<3)+(1U<<1)+(1U<<0)); + __m128i Q2 = _mm_clmulepi64_si128( A, C, 0x01); + __m128i Q3 = _mm_shuffle_epi8(_mm_setr_epi8(0, 27, 54, 45, 108, 119, 90, 65, (char)216, (char)195, (char)238, (char)245, (char)180, (char)175, (char)130, (char)153), + _mm_srli_si128(Q2,8)); + __m128i Q4 = _mm_xor_si128(Q2,A); + const __m128i final = _mm_xor_si128(Q3,Q4); + return final;/// WARNING: HIGH 64 BITS CONTAIN GARBAGE +} + + static inline __attribute__((always_inline)) uint64_t precompReduction64( __m128i A) { + return _mm_cvtsi128_si64(precompReduction64_si128(A)); +} + + static inline __attribute__((always_inline)) void fixupkey(__m128i **pMoveScratch, verusclhash_descr *pdesc) { + uint32_t ofs = pdesc->keySizeInBytes >> 4; + for (__m128i *pfixup = *pMoveScratch; pfixup; pfixup = *++pMoveScratch) + { + const __m128i fixup = _mm_load_si128((__m128i *)(pfixup + ofs)); + _mm_store_si128((__m128i *)pfixup, fixup); + } +} + + static inline __attribute__((always_inline)) void haraka512_keyed_local(unsigned char *out, const unsigned char *in, const u128 *rc) { + u128 s[4], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + s[2] = LOAD(in + 32); + s[3] = LOAD(in + 48); + + AES4(s[0], s[1], s[2], s[3], 0); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 8); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 16); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 24); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 32); + MIX4(s[0], s[1], s[2], s[3]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + s[2] = _mm_xor_si128(s[2], LOAD(in + 32)); + s[3] = _mm_xor_si128(s[3], LOAD(in + 48)); + + TRUNCSTORE(out, s[0], s[1], s[2], s[3]); +} + +// verus intermediate hash extra +__m128i __verusclmulwithoutreduction64alignedrepeat(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch) +{ + __m128i const *pbuf; + + // divide key mask by 16 from bytes to __m128i + keyMask >>= 4; + + // the random buffer must have at least 32 16 byte dwords after the keymask to work with this + // algorithm. we take the value from the last element inside the keyMask + 2, as that will never + // be used to xor into the accumulator before it is hashed with other values first + __m128i acc = _mm_load_si128(randomsource + (keyMask + 2)); + + for (int64_t i = 0; i < 32; i++) + { + const uint64_t selector = _mm_cvtsi128_si64(acc); + + // get two random locations in the key, which will be mutated and swapped + __m128i *prand = randomsource + ((selector >> 5) & keyMask); + __m128i *prandex = randomsource + ((selector >> 32) & keyMask); + + *(pMoveScratch++) = prand; + *(pMoveScratch++) = prandex; + + // select random start and order of pbuf processing + pbuf = buf + (selector & 3); + + switch (selector & 0x1c) + { + case 0: + { + const __m128i temp1 = _mm_load_si128(prandex); + const __m128i temp2 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prandex, tempb2); + break; + } + case 4: + { + const __m128i temp1 = _mm_load_si128(prand); + const __m128i temp2 = _mm_load_si128(pbuf); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + const __m128i clprod2 = _mm_clmulepi64_si128(temp2, temp2, 0x10); + acc = _mm_xor_si128(clprod2, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + acc = _mm_xor_si128(add12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prand, tempb2); + break; + } + case 8: + { + const __m128i temp1 = _mm_load_si128(prandex); + const __m128i temp2 = _mm_load_si128(pbuf); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + acc = _mm_xor_si128(add1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128(temp22, temp22, 0x10); + acc = _mm_xor_si128(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prandex, tempb2); + break; + } + case 0xc: + { + const __m128i temp1 = _mm_load_si128(prand); + const __m128i temp2 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + + // cannot be zero here + const int32_t divisor = (uint32_t)selector; + + acc = _mm_xor_si128(add1, acc); + + const int64_t dividend = _mm_cvtsi128_si64(acc); + const __m128i modulo = _mm_cvtsi32_si128(dividend % divisor); + acc = _mm_xor_si128(modulo, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + if (dividend & 1) + { + const __m128i temp12 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128(temp22, temp22, 0x10); + acc = _mm_xor_si128(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prand, tempb2); + } + else + { + const __m128i tempb3 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + _mm_store_si128(prand, tempb3); + } + break; + } + case 0x10: + { + // a few AES operations + const __m128i *rc = prand; + __m128i tmp; + + __m128i temp1 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + __m128i temp2 = _mm_load_si128(pbuf); + + AES2(temp1, temp2, 0); + MIX2(temp1, temp2); + + AES2(temp1, temp2, 4); + MIX2(temp1, temp2); + + AES2(temp1, temp2, 8); + MIX2(temp1, temp2); + + acc = _mm_xor_si128(temp2, _mm_xor_si128(temp1, acc)); + + const __m128i tempa1 = _mm_load_si128(prand); + const __m128i tempa2 = _mm_mulhrs_epi16(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa3); + _mm_store_si128(prand, tempa4); + break; + } + case 0x14: + { + // we'll just call this one the monkins loop, inspired by Chris + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + __m128i tmp; // used by MIX2 + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + uint64_t aesroundoffset = 0; + __m128i onekey; + + do + { + if (selector & (0x10000000 << rounds)) + { + onekey = _mm_load_si128(rc++); + const __m128i temp2 = _mm_load_si128(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + } + else + { + onekey = _mm_load_si128(rc++); + __m128i temp2 = _mm_load_si128(rounds & 1 ? buftmp : pbuf); + AES2(onekey, temp2, aesroundoffset); + aesroundoffset += 4; + MIX2(onekey, temp2); + acc = _mm_xor_si128(onekey, acc); + acc = _mm_xor_si128(temp2, acc); + } + } while (rounds--); + + const __m128i tempa1 = _mm_load_si128(prand); + const __m128i tempa2 = _mm_mulhrs_epi16(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa3); + _mm_store_si128(prand, tempa4); + break; + } + case 0x18: + { + const __m128i temp1 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i temp2 = _mm_load_si128(prand); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp2); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp2); + + const __m128i tempb3 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + _mm_store_si128(prand, tempb3); + break; + } + case 0x1c: + { + const __m128i temp1 = _mm_load_si128(pbuf); + const __m128i temp2 = _mm_load_si128(prandex); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp2); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp2); + + const __m128i tempa3 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + acc = _mm_xor_si128(tempa3, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, tempa3); + const __m128i tempb2 = _mm_xor_si128(tempb1, tempa3); + _mm_store_si128(prandex, tempb2); + break; + } + } + } + return acc; +} + +// hashes 64 bytes only by doing a carryless multiplication and reduction of the repeated 64 byte sequence 16 times, +// returning a 64 bit hash value +uint64_t verusclhash(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch) { + __m128i acc = __verusclmulwithoutreduction64alignedrepeat((__m128i *)random, (const __m128i *)buf, keyMask, pMoveScratch); + acc = _mm_xor_si128(acc, lazyLengthHash(1024, 64)); + return precompReduction64(acc); +} + +// hashes 64 bytes only by doing a carryless multiplication and reduction of the repeated 64 byte sequence 16 times, +// returning a 64 bit hash value +uint64_t verusclhash_sv2_1(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch) { + __m128i acc = __verusclmulwithoutreduction64alignedrepeat_sv2_1((__m128i *)random, (const __m128i *)buf, keyMask, pMoveScratch); + acc = _mm_xor_si128(acc, lazyLengthHash(1024, 64)); + return precompReduction64(acc); +} + +uint64_t verusclhash_sv2_2(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch) { + __m128i acc = __verusclmulwithoutreduction64alignedrepeat_sv2_2((__m128i *)random, (const __m128i *)buf, keyMask, pMoveScratch); + acc = _mm_xor_si128(acc, lazyLengthHash(1024, 64)); + return precompReduction64(acc); +} + +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_1(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch) +{ + const __m128i pbuf_copy[4] = {_mm_xor_si128(buf[0], buf[2]), _mm_xor_si128(buf[1], buf[3]), buf[2], buf[3]}; + const __m128i *pbuf; + + // divide key mask by 16 from bytes to __m128i + keyMask >>= 4; + + // the random buffer must have at least 32 16 byte dwords after the keymask to work with this + // algorithm. we take the value from the last element inside the keyMask + 2, as that will never + // be used to xor into the accumulator before it is hashed with other values first + __m128i acc = _mm_load_si128(randomsource + (keyMask + 2)); + + for (int64_t i = 0; i < 32; i++) + { + const uint64_t selector = _mm_cvtsi128_si64(acc); + + // get two random locations in the key, which will be mutated and swapped + __m128i *prand = randomsource + ((selector >> 5) & keyMask); + __m128i *prandex = randomsource + ((selector >> 32) & keyMask); + + *(pMoveScratch++) = prand; + *(pMoveScratch++) = prandex; + + // select random start and order of pbuf processing + pbuf = pbuf_copy + (selector & 3); + + switch (selector & 0x1c) + { + case 0: + { + const __m128i temp1 = _mm_load_si128(prandex); + const __m128i temp2 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prandex, tempb2); + break; + } + case 4: + { + const __m128i temp1 = _mm_load_si128(prand); + const __m128i temp2 = _mm_load_si128(pbuf); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + const __m128i clprod2 = _mm_clmulepi64_si128(temp2, temp2, 0x10); + acc = _mm_xor_si128(clprod2, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + acc = _mm_xor_si128(add12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prand, tempb2); + break; + } + case 8: + { + const __m128i temp1 = _mm_load_si128(prandex); + const __m128i temp2 = _mm_load_si128(pbuf); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + acc = _mm_xor_si128(add1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128(temp22, temp22, 0x10); + acc = _mm_xor_si128(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prandex, tempb2); + break; + } + case 0xc: + { + const __m128i temp1 = _mm_load_si128(prand); + const __m128i temp2 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + + // cannot be zero here + const int32_t divisor = (uint32_t)selector; + + acc = _mm_xor_si128(add1, acc); + + const int64_t dividend = _mm_cvtsi128_si64(acc); + const __m128i modulo = _mm_cvtsi32_si128(dividend % divisor); + acc = _mm_xor_si128(modulo, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + if (dividend & 1) + { + const __m128i temp12 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128(temp22, temp22, 0x10); + acc = _mm_xor_si128(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prand, tempb2); + } + else + { + const __m128i tempb3 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + _mm_store_si128(prand, tempb3); + } + break; + } + case 0x10: + { + // a few AES operations + const __m128i *rc = prand; + __m128i tmp; + + __m128i temp1 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + __m128i temp2 = _mm_load_si128(pbuf); + + AES2(temp1, temp2, 0); + MIX2(temp1, temp2); + + AES2(temp1, temp2, 4); + MIX2(temp1, temp2); + + AES2(temp1, temp2, 8); + MIX2(temp1, temp2); + + acc = _mm_xor_si128(temp2, _mm_xor_si128(temp1, acc)); + + const __m128i tempa1 = _mm_load_si128(prand); + const __m128i tempa2 = _mm_mulhrs_epi16(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa3); + _mm_store_si128(prand, tempa4); + break; + } + case 0x14: + { + // we'll just call this one the monkins loop, inspired by Chris - modified to cast to uint64_t on shift for more variability in the loop + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + __m128i tmp; // used by MIX2 + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + uint64_t aesroundoffset = 0; + __m128i onekey; + + do + { + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128(rc++); + const __m128i temp2 = _mm_load_si128(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + } + else + { + onekey = _mm_load_si128(rc++); + __m128i temp2 = _mm_load_si128(rounds & 1 ? buftmp : pbuf); + AES2(onekey, temp2, aesroundoffset); + aesroundoffset += 4; + MIX2(onekey, temp2); + acc = _mm_xor_si128(onekey, acc); + acc = _mm_xor_si128(temp2, acc); + } + } while (rounds--); + + const __m128i tempa1 = _mm_load_si128(prand); + const __m128i tempa2 = _mm_mulhrs_epi16(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa3); + _mm_store_si128(prand, tempa4); + break; + } + case 0x18: + { + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + __m128i onekey; + + do + { + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128(rc++); + const __m128i temp2 = _mm_load_si128(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128(onekey, temp2); + // cannot be zero here, may be negative + const int32_t divisor = (uint32_t)selector; + const int64_t dividend = _mm_cvtsi128_si64(add1); + const __m128i modulo = _mm_cvtsi32_si128(dividend % divisor); + acc = _mm_xor_si128(modulo, acc); + } + else + { + onekey = _mm_load_si128(rc++); + __m128i temp2 = _mm_load_si128(rounds & 1 ? buftmp : pbuf); + const __m128i add1 = _mm_xor_si128(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + const __m128i clprod2 = _mm_mulhrs_epi16(acc, clprod1); + acc = _mm_xor_si128(clprod2, acc); + } + } while (rounds--); + + const __m128i tempa3 = _mm_load_si128(prandex); + const __m128i tempa4 = _mm_xor_si128(tempa3, acc); + _mm_store_si128(prandex, tempa4); + _mm_store_si128(prand, onekey); + break; + } + case 0x1c: + { + const __m128i temp1 = _mm_load_si128(pbuf); + const __m128i temp2 = _mm_load_si128(prandex); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp2); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp2); + + const __m128i tempa3 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + acc = _mm_xor_si128(tempa3, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, tempa3); + const __m128i tempb2 = _mm_xor_si128(tempb1, tempa3); + _mm_store_si128(prandex, tempb2); + break; + } + } + } + return acc; +} + +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_2(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch) +{ + const __m128i pbuf_copy[4] = {_mm_xor_si128(buf[0], buf[2]), _mm_xor_si128(buf[1], buf[3]), buf[2], buf[3]}; + const __m128i *pbuf; + + // divide key mask by 16 from bytes to __m128i + keyMask >>= 4; + + // the random buffer must have at least 32 16 byte dwords after the keymask to work with this + // algorithm. we take the value from the last element inside the keyMask + 2, as that will never + // be used to xor into the accumulator before it is hashed with other values first + __m128i acc = _mm_load_si128(randomsource + (keyMask + 2)); + + for (int64_t i = 0; i < 32; i++) + { + const uint64_t selector = _mm_cvtsi128_si64(acc); + + // get two random locations in the key, which will be mutated and swapped + __m128i *prand = randomsource + ((selector >> 5) & keyMask); + __m128i *prandex = randomsource + ((selector >> 32) & keyMask); + + *(pMoveScratch++) = prand; + *(pMoveScratch++) = prandex; + + // select random start and order of pbuf processing + pbuf = pbuf_copy + (selector & 3); + + switch (selector & 0x1c) + { + case 0: + { + const __m128i temp1 = _mm_load_si128(prandex); + const __m128i temp2 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prandex, tempb2); + break; + } + case 4: + { + const __m128i temp1 = _mm_load_si128(prand); + const __m128i temp2 = _mm_load_si128(pbuf); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + const __m128i clprod2 = _mm_clmulepi64_si128(temp2, temp2, 0x10); + acc = _mm_xor_si128(clprod2, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + acc = _mm_xor_si128(add12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prand, tempb2); + break; + } + case 8: + { + const __m128i temp1 = _mm_load_si128(prandex); + const __m128i temp2 = _mm_load_si128(pbuf); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + acc = _mm_xor_si128(add1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128(temp22, temp22, 0x10); + acc = _mm_xor_si128(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prandex, tempb2); + break; + } + case 0xc: + { + const __m128i temp1 = _mm_load_si128(prand); + const __m128i temp2 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + + // cannot be zero here + const int32_t divisor = (uint32_t)selector; + + acc = _mm_xor_si128(add1, acc); + + const int64_t dividend = _mm_cvtsi128_si64(acc); + const __m128i modulo = _mm_cvtsi32_si128(dividend % divisor); + acc = _mm_xor_si128(modulo, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp1); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp1); + + if (dividend & 1) + { + const __m128i temp12 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128(pbuf); + const __m128i add12 = _mm_xor_si128(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128(add12, add12, 0x10); + acc = _mm_xor_si128(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128(temp22, temp22, 0x10); + acc = _mm_xor_si128(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16(acc, temp12); + const __m128i tempb2 = _mm_xor_si128(tempb1, temp12); + _mm_store_si128(prand, tempb2); + } + else + { + const __m128i tempb3 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa2); + _mm_store_si128(prand, tempb3); + const __m128i tempb4 = _mm_load_si128(pbuf); + acc = _mm_xor_si128(tempb4, acc); + } + break; + } + case 0x10: + { + // a few AES operations + const __m128i *rc = prand; + __m128i tmp; + + __m128i temp1 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + __m128i temp2 = _mm_load_si128(pbuf); + + AES2(temp1, temp2, 0); + MIX2(temp1, temp2); + + AES2(temp1, temp2, 4); + MIX2(temp1, temp2); + + AES2(temp1, temp2, 8); + MIX2(temp1, temp2); + + acc = _mm_xor_si128(temp2, _mm_xor_si128(temp1, acc)); + + const __m128i tempa1 = _mm_load_si128(prand); + const __m128i tempa2 = _mm_mulhrs_epi16(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa3); + _mm_store_si128(prand, tempa4); + break; + } + case 0x14: + { + // we'll just call this one the monkins loop, inspired by Chris - modified to cast to uint64_t on shift for more variability in the loop + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + __m128i tmp; // used by MIX2 + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + uint64_t aesroundoffset = 0; + __m128i onekey; + + do + { + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128(rc++); + const __m128i temp2 = _mm_load_si128(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + } + else + { + onekey = _mm_load_si128(rc++); + __m128i temp2 = _mm_load_si128(rounds & 1 ? buftmp : pbuf); + AES2(onekey, temp2, aesroundoffset); + aesroundoffset += 4; + MIX2(onekey, temp2); + acc = _mm_xor_si128(onekey, acc); + acc = _mm_xor_si128(temp2, acc); + } + } while (rounds--); + + const __m128i tempa1 = _mm_load_si128(prand); + const __m128i tempa2 = _mm_mulhrs_epi16(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128(prandex); + _mm_store_si128(prandex, tempa3); + _mm_store_si128(prand, tempa4); + break; + } + case 0x18: + { + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + __m128i onekey; + + do + { + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128(rc++); + const __m128i temp2 = _mm_load_si128(rounds & 1 ? pbuf : buftmp); + onekey = _mm_xor_si128(onekey, temp2); + // cannot be zero here, may be negative + const int32_t divisor = (uint32_t)selector; + const int64_t dividend = _mm_cvtsi128_si64(onekey); + const __m128i modulo = _mm_cvtsi32_si128(dividend % divisor); + acc = _mm_xor_si128(modulo, acc); + } + else + { + onekey = _mm_load_si128(rc++); + __m128i temp2 = _mm_load_si128(rounds & 1 ? buftmp : pbuf); + const __m128i add1 = _mm_xor_si128(onekey, temp2); + onekey = _mm_clmulepi64_si128(add1, add1, 0x10); + const __m128i clprod2 = _mm_mulhrs_epi16(acc, onekey); + acc = _mm_xor_si128(clprod2, acc); + } + } while (rounds--); + + const __m128i tempa3 = _mm_load_si128(prandex); + const __m128i tempa4 = _mm_xor_si128(tempa3, acc); + + _mm_store_si128(prandex, onekey); + _mm_store_si128(prand, tempa4); + break; + } + case 0x1c: + { + const __m128i temp1 = _mm_load_si128(pbuf); + const __m128i temp2 = _mm_load_si128(prandex); + const __m128i add1 = _mm_xor_si128(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128(add1, add1, 0x10); + acc = _mm_xor_si128(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16(acc, temp2); + const __m128i tempa2 = _mm_xor_si128(tempa1, temp2); + + const __m128i tempa3 = _mm_load_si128(prand); + _mm_store_si128(prand, tempa2); + + acc = _mm_xor_si128(tempa3, acc); + const __m128i temp4 = _mm_load_si128(pbuf - (((selector & 1) << 1) - 1)); + acc = _mm_xor_si128(temp4,acc); + const __m128i tempb1 = _mm_mulhrs_epi16(acc, tempa3); + const __m128i tempb2 = _mm_xor_si128(tempb1, tempa3); + _mm_store_si128(prandex, tempb2); + break; + } + } + } + return acc; +} + +void *alloc_aligned_buffer(uint64_t bufSize) +{ + void *answer = NULL; + if (posix_memalign(&answer, sizeof(__m128i)*2, bufSize)) + { + return NULL; + } + else + { + return answer; + } +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/verus_clhash.h b/src/Native/libverushash/crypto/verus_clhash.h new file mode 100644 index 000000000..1f578c5e6 --- /dev/null +++ b/src/Native/libverushash/crypto/verus_clhash.h @@ -0,0 +1,304 @@ +/* + * This uses variations of the clhash algorithm for Verus Coin, licensed + * with the Apache-2.0 open source license. + * + * Copyright (c) 2018 Michael Toutonghi + * Distributed under the Apache 2.0 software license, available in the original form for clhash + * here: https://github.com/lemire/clhash/commit/934da700a2a54d8202929a826e2763831bd43cf7#diff-9879d6db96fd29134fc802214163b95a + * + * CLHash is a very fast hashing function that uses the + * carry-less multiplication and SSE instructions. + * + * Original CLHash code (C) 2017, 2018 Daniel Lemire and Owen Kaser + * Faster 64-bit universal hashing + * using carry-less multiplications, Journal of Cryptographic Engineering (to appear) + * + * Best used on recent x64 processors (Haswell or better). + * + **/ + +#ifndef INCLUDE_VERUS_CLHASH_H +#define INCLUDE_VERUS_CLHASH_H + +#ifndef _WIN32 +#include +#include +#else +#include +#endif // !WIN32 + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno) +typedef unsigned char u_char; +#endif + +enum { + // Verus Key size must include the equivalent size of a Haraka key + // after the first part. + // Any excess over a power of 2 will not get mutated, and any excess over + // power of 2 + Haraka sized key will not be used + VERUSKEYSIZE=1024 * 8 + (40 * 16), + SOLUTION_VERUSHHASH_V2 = 1, // this must be in sync with CScript::SOLUTION_VERUSV2 + SOLUTION_VERUSHHASH_V2_1 = 3, // this must be in sync with CScript::ACTIVATE_VERUSHASH2_1 + SOLUTION_VERUSHHASH_V2_2 = 4 +}; + +struct verusclhash_descr +{ + uint256 seed; + uint32_t keySizeInBytes; +}; + +struct thread_specific_ptr { + void *ptr; + thread_specific_ptr() { ptr = NULL; } + void reset(void *newptr = NULL) + { + if (ptr && ptr != newptr) + { + std::free(ptr); + } + ptr = newptr; + + } + void *get() { return ptr; } +#if defined(__APPLE__) || defined(_WIN32) + // horrible MingW and Mac with gcc thread local storage bug workaround + ~thread_specific_ptr(); +#else + ~thread_specific_ptr() { + this->reset(); + } +#endif +}; + +extern thread_local thread_specific_ptr verusclhasher_key; +extern thread_local thread_specific_ptr verusclhasher_descr; + +extern int __cpuverusoptimized; + +__m128i __verusclmulwithoutreduction64alignedrepeat(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_1(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_2(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); +__m128i __verusclmulwithoutreduction64alignedrepeat_port(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_1_port(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_2_port(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); + +inline bool IsCPUVerusOptimized() +{ + #if defined(__arm__) || defined(__aarch64__) + long hwcaps= getauxval(AT_HWCAP); + + if((hwcaps & HWCAP_AES) && (hwcaps & HWCAP_PMULL)) + __cpuverusoptimized = true; + else + __cpuverusoptimized = false; + + #else + if (__cpuverusoptimized & 0x80) + { + unsigned int eax,ebx,ecx,edx; + if (!__get_cpuid(1,&eax,&ebx,&ecx,&edx)) + { + __cpuverusoptimized = false; + } + else + { + __cpuverusoptimized = ((ecx & (bit_AVX | bit_AES | bit_PCLMUL)) == (bit_AVX | bit_AES | bit_PCLMUL)); + } + } + #endif + return __cpuverusoptimized; +}; + +inline void ForceCPUVerusOptimized(bool trueorfalse) +{ + __cpuverusoptimized = trueorfalse; +}; + +uint64_t verusclhash(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch); +uint64_t verusclhash_port(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch); +uint64_t verusclhash_sv2_1(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch); +uint64_t verusclhash_sv2_1_port(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch); +uint64_t verusclhash_sv2_2(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch); +uint64_t verusclhash_sv2_2_port(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch); +void *alloc_aligned_buffer(uint64_t bufSize); + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +// special high speed hasher for VerusHash 2.0 +struct verusclhasher { + uint64_t keySizeInBytes; + uint64_t keyMask; + uint64_t (*verusclhashfunction)(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch); + __m128i (*verusinternalclhashfunction)(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch); + + static inline uint64_t keymask(uint64_t keysize) + { + int i = 0; + while (keysize >>= 1) + { + i++; + } + return i ? (((uint64_t)1) << i) - 1 : 0; + } + + // align on 256 bit boundary at end + verusclhasher(uint64_t keysize=VERUSKEYSIZE, int solutionVersion=SOLUTION_VERUSHHASH_V2) : keySizeInBytes((keysize >> 5) << 5) + { +#ifdef __APPLE__ + __tls_init(); +#endif + if (IsCPUVerusOptimized()) + { + if (solutionVersion >= SOLUTION_VERUSHHASH_V2_1) + { + if (solutionVersion >= SOLUTION_VERUSHHASH_V2_2) + { + verusclhashfunction = &verusclhash_sv2_2; + verusinternalclhashfunction = &__verusclmulwithoutreduction64alignedrepeat_sv2_2; + } + else + { + verusclhashfunction = &verusclhash_sv2_1; + verusinternalclhashfunction = &__verusclmulwithoutreduction64alignedrepeat_sv2_1; + } + } + else + { + verusclhashfunction = &verusclhash; + verusinternalclhashfunction = &__verusclmulwithoutreduction64alignedrepeat; + } + } + else + { + if (solutionVersion >= SOLUTION_VERUSHHASH_V2_1) + { + if (solutionVersion >= SOLUTION_VERUSHHASH_V2_2) + { + verusclhashfunction = &verusclhash_sv2_2_port; + verusinternalclhashfunction = &__verusclmulwithoutreduction64alignedrepeat_sv2_2_port; + } + else + { + verusclhashfunction = &verusclhash_sv2_1_port; + verusinternalclhashfunction = &__verusclmulwithoutreduction64alignedrepeat_sv2_1_port; + } + } + else + { + verusclhashfunction = &verusclhash_port; + verusinternalclhashfunction = &__verusclmulwithoutreduction64alignedrepeat_port; + } + } + + // if we changed, change it + if (verusclhasher_key.get() && keySizeInBytes != ((verusclhash_descr *)verusclhasher_descr.get())->keySizeInBytes) + { + verusclhasher_key.reset(); + verusclhasher_descr.reset(); + } + // get buffer space for mutating and refresh keys + void *key = NULL; + if (!(key = verusclhasher_key.get()) && + (verusclhasher_key.reset((unsigned char *)alloc_aligned_buffer(keySizeInBytes << 1)), key = verusclhasher_key.get())) + { + verusclhash_descr *pdesc; + if (verusclhasher_descr.reset(new verusclhash_descr()), pdesc = (verusclhash_descr *)verusclhasher_descr.get()) + { + pdesc->keySizeInBytes = keySizeInBytes; + } + else + { + verusclhasher_key.reset(); + key = NULL; + } + } + if (key) + { + keyMask = keymask(keySizeInBytes); + } + else + { + keyMask = 0; + keySizeInBytes = 0; + } +#ifdef VERUSHASHDEBUG + printf("New hasher, keyMask: %lx, newKeySize: %lx\n", keyMask, keySizeInBytes); +#endif + } + + inline void *gethasherrefresh() + { + verusclhash_descr *pdesc = (verusclhash_descr *)verusclhasher_descr.get(); + return (unsigned char *)verusclhasher_key.get() + pdesc->keySizeInBytes; + } + + // returns a per thread, writeable scratch pad that has enough space to hold a pointer for each + // mutated entry in the refresh hash + inline __m128i **getpmovescratch(void *hasherrefresh) + { + return (__m128i **)((unsigned char *)hasherrefresh + keyrefreshsize()); + } + + inline verusclhash_descr *gethasherdescription() const + { + return (verusclhash_descr *)verusclhasher_descr.get(); + } + + inline uint64_t keyrefreshsize() const + { + return keyMask + 1; + } + + inline void *fixupkey(void *hashKey, verusclhash_descr &desc) + { + unsigned char *ret = (unsigned char *)hashKey; + uint32_t ofs = desc.keySizeInBytes >> 4; + __m128i **ppfixup = getpmovescratch(ret + desc.keySizeInBytes); // past the part to refresh from + for (__m128i *pfixup = *ppfixup; pfixup; pfixup = *++ppfixup) + { + *pfixup = *(pfixup + ofs); // we hope the compiler cancels this operation out before add + } + return hashKey; + } + + // this prepares a key for hashing and mutation by copying it from the original key for this block + // WARNING!! this does not check for NULL ptr, so make sure the buffer is allocated + inline void *gethashkey() + { + unsigned char *ret = (unsigned char *)verusclhasher_key.get(); + return fixupkey(ret, *(verusclhash_descr *)verusclhasher_descr.get()); + } + + inline uint64_t operator()(const unsigned char buf[64]) const { + unsigned char *pkey = (unsigned char *)verusclhasher_key.get(); + verusclhash_descr *pdesc = (verusclhash_descr *)verusclhasher_descr.get(); + return (*verusclhashfunction)(pkey, buf, keyMask, (__m128i **)(pkey + (pdesc->keySizeInBytes + keyrefreshsize()))); + } + + inline uint64_t operator()(const unsigned char buf[64], void *pkey) const { + verusclhash_descr *pdesc = (verusclhash_descr *)verusclhasher_descr.get(); + return (*verusclhashfunction)(pkey, buf, keyMask, (__m128i **)((unsigned char *)pkey + (pdesc->keySizeInBytes + keyrefreshsize()))); + } + + inline uint64_t operator()(const unsigned char buf[64], void *pkey, __m128i **pMoveScratch) const { + return (*verusclhashfunction)((unsigned char *)pkey, buf, keyMask, pMoveScratch); + } +}; + +#endif // #ifdef __cplusplus + +#endif // INCLUDE_VERUS_CLHASH_H \ No newline at end of file diff --git a/src/Native/libverushash/crypto/verus_clhash_portable.cpp b/src/Native/libverushash/crypto/verus_clhash_portable.cpp new file mode 100644 index 000000000..8622b5bde --- /dev/null +++ b/src/Native/libverushash/crypto/verus_clhash_portable.cpp @@ -0,0 +1,1199 @@ +/* + * This uses veriations of the clhash algorithm for Verus Coin, licensed + * with the Apache-2.0 open source license. + * + * Copyright (c) 2018 Michael Toutonghi + * Distributed under the Apache 2.0 software license, available in the original form for clhash + * here: https://github.com/lemire/clhash/commit/934da700a2a54d8202929a826e2763831bd43cf7#diff-9879d6db96fd29134fc802214163b95a + * + * Original CLHash code and any portions herein, (C) 2017, 2018 Daniel Lemire and Owen Kaser + * Faster 64-bit universal hashing + * using carry-less multiplications, Journal of Cryptographic Engineering (to appear) + * + * Best used on recent x64 processors (Haswell or better). + * + * This implements an intermediate step in the last part of a Verus block hash. The intent of this step + * is to more effectively equalize FPGAs over GPUs and CPUs. + * + **/ + + +#include "verus_hash.h" + +#include +#include + +#ifdef __APPLE__ +#include +#endif// APPLE + +#ifdef __linux__ + +#if defined(__i386__) || defined(__X86_64__) +#include +#elif defined(__arm__) || defined(__aarch64__) +#include "crypto/SSE2NEON.h" +#endif + +#elif _WIN32 +#pragma warning (disable : 4146) +#include +#endif + +void clmul64(uint64_t a, uint64_t b, uint64_t* r) +{ + uint8_t s = 4,i; //window size + uint64_t two_s = 1 << s; //2^s + uint64_t smask = two_s-1; //s 1 bits + uint64_t u[16]; + uint64_t tmp; + uint64_t ifmask; + //Precomputation + u[0] = 0; + u[1] = b; + for(i = 2 ; i < two_s; i += 2){ + u[i] = u[i >> 1] << 1; //even indices: left shift + u[i + 1] = u[i] ^ b; //odd indices: xor b + } + //Multiply + r[0] = u[a & smask]; //first window only affects lower word + r[1] = 0; + for(i = s ; i < 64 ; i += s){ + tmp = u[a >> i & smask]; + r[0] ^= tmp << i; + r[1] ^= tmp >> (64 - i); + } + //Repair + uint64_t m = 0xEEEEEEEEEEEEEEEE; //s=4 => 16 times 1110 + for(i = 1 ; i < s ; i++){ + tmp = ((a & m) >> i); + m &= m << 1; //shift mask to exclude all bit j': j' mod s = i + ifmask = -((b >> (64-i)) & 1); //if the (64-i)th bit of b is 1 + r[1] ^= (tmp & ifmask); + } +} + +u128 _mm_clmulepi64_si128_emu(const __m128i &a, const __m128i &b, int imm) +{ + uint64_t result[2]; + clmul64(*((uint64_t*)&a + (imm & 1)), *((uint64_t*)&b + ((imm & 0x10) >> 4)), result); + + /* + // TEST + const __m128i tmp1 = _mm_load_si128(&a); + const __m128i tmp2 = _mm_load_si128(&b); + imm = imm & 0x11; + const __m128i testresult = (imm == 0x10) ? _mm_clmulepi64_si128(tmp1, tmp2, 0x10) : ((imm == 0x01) ? _mm_clmulepi64_si128(tmp1, tmp2, 0x01) : ((imm == 0x00) ? _mm_clmulepi64_si128(tmp1, tmp2, 0x00) : _mm_clmulepi64_si128(tmp1, tmp2, 0x11))); + if (!memcmp(&testresult, &result, 16)) + { + printf("_mm_clmulepi64_si128_emu: Portable version passed!\n"); + } + else + { + printf("_mm_clmulepi64_si128_emu: Portable version failed! a: %lxh %lxl, b: %lxh %lxl, imm: %x, emu: %lxh %lxl, intrin: %lxh %lxl\n", + *((uint64_t *)&a + 1), *(uint64_t *)&a, + *((uint64_t *)&b + 1), *(uint64_t *)&b, + imm, + *((uint64_t *)result + 1), *(uint64_t *)result, + *((uint64_t *)&testresult + 1), *(uint64_t *)&testresult); + return testresult; + } + */ + + return *(__m128i *)result; +} + +u128 _mm_mulhrs_epi16_emu(__m128i _a, __m128i _b) +{ + int16_t result[8]; + int16_t *a = (int16_t*)&_a, *b = (int16_t*)&_b; + for (int i = 0; i < 8; i ++) + { + result[i] = (int16_t)((((int32_t)(a[i]) * (int32_t)(b[i])) + 0x4000) >> 15); + } + + /* + const __m128i testresult = _mm_mulhrs_epi16(_a, _b); + if (!memcmp(&testresult, &result, 16)) + { + printf("_mm_mulhrs_epi16_emu: Portable version passed!\n"); + } + else + { + printf("_mm_mulhrs_epi16_emu: Portable version failed! a: %lxh %lxl, b: %lxh %lxl, emu: %lxh %lxl, intrin: %lxh %lxl\n", + *((uint64_t *)&a + 1), *(uint64_t *)&a, + *((uint64_t *)&b + 1), *(uint64_t *)&b, + *((uint64_t *)result + 1), *(uint64_t *)result, + *((uint64_t *)&testresult + 1), *(uint64_t *)&testresult); + } + */ + + return *(__m128i *)result; +} + +inline u128 _mm_set_epi64x_emu(uint64_t hi, uint64_t lo) +{ + __m128i result; + ((uint64_t *)&result)[0] = lo; + ((uint64_t *)&result)[1] = hi; + return result; +} + +inline u128 _mm_cvtsi64_si128_emu(uint64_t lo) +{ + __m128i result; + ((uint64_t *)&result)[0] = lo; + ((uint64_t *)&result)[1] = 0; + return result; +} + +inline int64_t _mm_cvtsi128_si64_emu(const __m128i &a) +{ + return *(int64_t *)&a; +} + +inline int32_t _mm_cvtsi128_si32_emu(const __m128i &a) +{ + return *(int32_t *)&a; +} + +inline u128 _mm_cvtsi32_si128_emu(uint32_t lo) +{ + __m128i result; + ((uint32_t *)&result)[0] = lo; + ((uint32_t *)&result)[1] = 0; + ((uint64_t *)&result)[1] = 0; + + /* + const __m128i testresult = _mm_cvtsi32_si128(lo); + if (!memcmp(&testresult, &result, 16)) + { + printf("_mm_cvtsi32_si128_emu: Portable version passed!\n"); + } + else + { + printf("_mm_cvtsi32_si128_emu: Portable version failed!\n"); + } + */ + + return result; +} + +u128 _mm_setr_epi8_emu(u_char c0, u_char c1, u_char c2, u_char c3, u_char c4, u_char c5, u_char c6, u_char c7, u_char c8, u_char c9, u_char c10, u_char c11, u_char c12, u_char c13, u_char c14, u_char c15) +{ + __m128i result; + ((uint8_t *)&result)[0] = c0; + ((uint8_t *)&result)[1] = c1; + ((uint8_t *)&result)[2] = c2; + ((uint8_t *)&result)[3] = c3; + ((uint8_t *)&result)[4] = c4; + ((uint8_t *)&result)[5] = c5; + ((uint8_t *)&result)[6] = c6; + ((uint8_t *)&result)[7] = c7; + ((uint8_t *)&result)[8] = c8; + ((uint8_t *)&result)[9] = c9; + ((uint8_t *)&result)[10] = c10; + ((uint8_t *)&result)[11] = c11; + ((uint8_t *)&result)[12] = c12; + ((uint8_t *)&result)[13] = c13; + ((uint8_t *)&result)[14] = c14; + ((uint8_t *)&result)[15] = c15; + + /* + const __m128i testresult = _mm_setr_epi8(c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15); + if (!memcmp(&testresult, &result, 16)) + { + printf("_mm_setr_epi8_emu: Portable version passed!\n"); + } + else + { + printf("_mm_setr_epi8_emu: Portable version failed!\n"); + } + */ + + return result; +} + +inline __m128i _mm_srli_si128_emu(__m128i a, int imm8) +{ + unsigned char result[16]; + uint8_t shift = imm8 & 0xff; + if (shift > 15) shift = 16; + + int i; + for (i = 0; i < (16 - shift); i++) + { + result[i] = ((unsigned char *)&a)[shift + i]; + } + for ( ; i < 16; i++) + { + result[i] = 0; + } + + /* + const __m128i tmp1 = _mm_load_si128(&a); + __m128i testresult = _mm_srli_si128(tmp1, imm8); + if (!memcmp(&testresult, result, 16)) + { + printf("_mm_srli_si128_emu: Portable version passed!\n"); + } + else + { + printf("_mm_srli_si128_emu: Portable version failed! val: %lx%lx imm: %x emu: %lx%lx, intrin: %lx%lx\n", + *((uint64_t *)&a + 1), *(uint64_t *)&a, + imm8, + *((uint64_t *)result + 1), *(uint64_t *)result, + *((uint64_t *)&testresult + 1), *(uint64_t *)&testresult); + } + */ + + return *(__m128i *)result; +} + +inline __m128i _mm_xor_si128_emu(__m128i a, __m128i b) +{ +#ifdef _WIN32 + uint64_t result[2]; + result[0] = *(uint64_t *)&a ^ *(uint64_t *)&b; + result[1] = *((uint64_t *)&a + 1) ^ *((uint64_t *)&b + 1); + return *(__m128i *)result; +#else + return a ^ b; +#endif +} + +inline __m128i _mm_load_si128_emu(const void *p) +{ + return *(__m128i *)p; +} + +inline void _mm_store_si128_emu(void *p, __m128i val) +{ + *(__m128i *)p = val; +} + +__m128i _mm_shuffle_epi8_emu(__m128i a, __m128i b) +{ + __m128i result; + for (int i = 0; i < 16; i++) + { + if (((uint8_t *)&b)[i] & 0x80) + { + ((uint8_t *)&result)[i] = 0; + } + else + { + ((uint8_t *)&result)[i] = ((uint8_t *)&a)[((uint8_t *)&b)[i] & 0xf]; + } + } + + /* + const __m128i tmp1 = _mm_load_si128(&a); + const __m128i tmp2 = _mm_load_si128(&b); + __m128i testresult = _mm_shuffle_epi8(tmp1, tmp2); + if (!memcmp(&testresult, &result, 16)) + { + printf("_mm_shuffle_epi8_emu: Portable version passed!\n"); + } + else + { + printf("_mm_shuffle_epi8_emu: Portable version failed!\n"); + } + */ + + return result; +} + +// portable +static inline __m128i lazyLengthHash_port(uint64_t keylength, uint64_t length) { + const __m128i lengthvector = _mm_set_epi64x_emu(keylength,length); + const __m128i clprod1 = _mm_clmulepi64_si128_emu( lengthvector, lengthvector, 0x10); + return clprod1; +} + +// modulo reduction to 64-bit value. The high 64 bits contain garbage, see precompReduction64 +static inline __m128i precompReduction64_si128_port( __m128i A) { + + //const __m128i C = _mm_set_epi64x(1U,(1U<<4)+(1U<<3)+(1U<<1)+(1U<<0)); // C is the irreducible poly. (64,4,3,1,0) + const __m128i C = _mm_cvtsi64_si128_emu((1U<<4)+(1U<<3)+(1U<<1)+(1U<<0)); + __m128i Q2 = _mm_clmulepi64_si128_emu( A, C, 0x01); + __m128i Q3 = _mm_shuffle_epi8_emu(_mm_setr_epi8_emu(0, 27, 54, 45, 108, 119, 90, 65, (char)216, (char)195, (char)238, (char)245, (char)180, (char)175, (char)130, (char)153), + _mm_srli_si128_emu(Q2,8)); + __m128i Q4 = _mm_xor_si128_emu(Q2,A); + const __m128i final = _mm_xor_si128_emu(Q3,Q4); + return final;/// WARNING: HIGH 64 BITS SHOULD BE ASSUMED TO CONTAIN GARBAGE +} + +static inline uint64_t precompReduction64_port( __m128i A) { + __m128i tmp = precompReduction64_si128_port(A); + return _mm_cvtsi128_si64_emu(tmp); +} + +// verus intermediate hash extra +__m128i __verusclmulwithoutreduction64alignedrepeat_port(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch) +{ + __m128i const *pbuf; + + // divide key mask by 16 from bytes to __m128i + keyMask >>= 4; + + // the random buffer must have at least 32 16 byte dwords after the keymask to work with this + // algorithm. we take the value from the last element inside the keyMask + 2, as that will never + // be used to xor into the accumulator before it is hashed with other values first + __m128i acc = _mm_load_si128_emu(randomsource + (keyMask + 2)); + + for (int64_t i = 0; i < 32; i++) + { + const uint64_t selector = _mm_cvtsi128_si64_emu(acc); + + // get two random locations in the key, which will be mutated and swapped + __m128i *prand = randomsource + ((selector >> 5) & keyMask); + __m128i *prandex = randomsource + ((selector >> 32) & keyMask); + + *pMoveScratch++ = prand; + *pMoveScratch++ = prandex; + + // select random start and order of pbuf processing + pbuf = buf + (selector & 3); + + switch (selector & 0x1c) + { + case 0: + { + const __m128i temp1 = _mm_load_si128_emu(prandex); + const __m128i temp2 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prandex, tempb2); + break; + } + case 4: + { + const __m128i temp1 = _mm_load_si128_emu(prand); + const __m128i temp2 = _mm_load_si128_emu(pbuf); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + const __m128i clprod2 = _mm_clmulepi64_si128_emu(temp2, temp2, 0x10); + acc = _mm_xor_si128_emu(clprod2, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + acc = _mm_xor_si128_emu(add12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prand, tempb2); + break; + } + case 8: + { + const __m128i temp1 = _mm_load_si128_emu(prandex); + const __m128i temp2 = _mm_load_si128_emu(pbuf); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + acc = _mm_xor_si128_emu(add1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128_emu(temp22, temp22, 0x10); + acc = _mm_xor_si128_emu(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prandex, tempb2); + break; + } + case 0xc: + { + const __m128i temp1 = _mm_load_si128_emu(prand); + const __m128i temp2 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + + // cannot be zero here + const int32_t divisor = (uint32_t)selector; + + acc = _mm_xor_si128_emu(add1, acc); + + const int64_t dividend = _mm_cvtsi128_si64_emu(acc); + const __m128i modulo = _mm_cvtsi32_si128_emu(dividend % divisor); + acc = _mm_xor_si128_emu(modulo, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + if (dividend & 1) + { + const __m128i temp12 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128_emu(temp22, temp22, 0x10); + acc = _mm_xor_si128_emu(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prand, tempb2); + } + else + { + const __m128i tempb3 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + _mm_store_si128_emu(prand, tempb3); + } + break; + } + case 0x10: + { + // a few AES operations + const __m128i *rc = prand; + __m128i tmp; + + __m128i temp1 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + __m128i temp2 = _mm_load_si128_emu(pbuf); + + AES2_EMU(temp1, temp2, 0); + MIX2_EMU(temp1, temp2); + + AES2_EMU(temp1, temp2, 4); + MIX2_EMU(temp1, temp2); + + AES2_EMU(temp1, temp2, 8); + MIX2_EMU(temp1, temp2); + + acc = _mm_xor_si128_emu(temp1, acc); + acc = _mm_xor_si128_emu(temp2, acc); + + const __m128i tempa1 = _mm_load_si128_emu(prand); + const __m128i tempa2 = _mm_mulhrs_epi16_emu(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128_emu(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa3); + _mm_store_si128_emu(prand, tempa4); + break; + } + case 0x14: + { + // we'll just call this one the monkins loop, inspired by Chris + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + __m128i tmp; // used by MIX2 + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + uint64_t aesround = 0; + __m128i onekey; + + do + { + // note that due to compiler and CPUs, we expect this to do: + // if (selector & ((0x10000000 << rounds) & 0xffffffff) if rounds != 3 else selector & 0xffffffff80000000): + if (selector & (0x10000000 << rounds)) + { + onekey = _mm_load_si128_emu(rc++); + const __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128_emu(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + } + else + { + onekey = _mm_load_si128_emu(rc++); + __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? buftmp : pbuf); + const uint64_t roundidx = aesround++ << 2; + AES2_EMU(onekey, temp2, roundidx); + + MIX2_EMU(onekey, temp2); + + acc = _mm_xor_si128_emu(onekey, acc); + acc = _mm_xor_si128_emu(temp2, acc); + } + } while (rounds--); + + const __m128i tempa1 = _mm_load_si128_emu(prand); + const __m128i tempa2 = _mm_mulhrs_epi16_emu(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128_emu(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa3); + _mm_store_si128_emu(prand, tempa4); + break; + } + case 0x18: + { + const __m128i temp1 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i temp2 = _mm_load_si128_emu(prand); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp2); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp2); + + const __m128i tempb3 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + _mm_store_si128_emu(prand, tempb3); + break; + } + case 0x1c: + { + const __m128i temp1 = _mm_load_si128_emu(pbuf); + const __m128i temp2 = _mm_load_si128_emu(prandex); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp2); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp2); + + const __m128i tempa3 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + acc = _mm_xor_si128_emu(tempa3, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, tempa3); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, tempa3); + _mm_store_si128_emu(prandex, tempb2); + break; + } + } + } + return acc; +} + +// verus intermediate hash extra +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_1_port(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch) +{ + const __m128i pbuf_copy[4] = {_mm_xor_si128(buf[0],buf[2]), _mm_xor_si128(buf[1],buf[3]), buf[2], buf[3]}; + const __m128i *pbuf; + + // divide key mask by 16 from bytes to __m128i + keyMask >>= 4; + + // the random buffer must have at least 32 16 byte dwords after the keymask to work with this + // algorithm. we take the value from the last element inside the keyMask + 2, as that will never + // be used to xor into the accumulator before it is hashed with other values first + __m128i acc = _mm_load_si128_emu(randomsource + (keyMask + 2)); + + for (int64_t i = 0; i < 32; i++) + { + const uint64_t selector = _mm_cvtsi128_si64_emu(acc); + + // get two random locations in the key, which will be mutated and swapped + __m128i *prand = randomsource + ((selector >> 5) & keyMask); + __m128i *prandex = randomsource + ((selector >> 32) & keyMask); + + *pMoveScratch++ = prand; + *pMoveScratch++ = prandex; + + // select random start and order of pbuf processing + pbuf = pbuf_copy + (selector & 3); + + switch (selector & 0x1c) + { + case 0: + { + const __m128i temp1 = _mm_load_si128_emu(prandex); + const __m128i temp2 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prandex, tempb2); + break; + } + case 4: + { + const __m128i temp1 = _mm_load_si128_emu(prand); + const __m128i temp2 = _mm_load_si128_emu(pbuf); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + const __m128i clprod2 = _mm_clmulepi64_si128_emu(temp2, temp2, 0x10); + acc = _mm_xor_si128_emu(clprod2, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + acc = _mm_xor_si128_emu(add12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prand, tempb2); + break; + } + case 8: + { + const __m128i temp1 = _mm_load_si128_emu(prandex); + const __m128i temp2 = _mm_load_si128_emu(pbuf); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + acc = _mm_xor_si128_emu(add1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128_emu(temp22, temp22, 0x10); + acc = _mm_xor_si128_emu(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prandex, tempb2); + break; + } + case 0xc: + { + const __m128i temp1 = _mm_load_si128_emu(prand); + const __m128i temp2 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + + // cannot be zero here + const int32_t divisor = (uint32_t)selector; + + acc = _mm_xor_si128_emu(add1, acc); + + const int64_t dividend = _mm_cvtsi128_si64_emu(acc); + const __m128i modulo = _mm_cvtsi32_si128_emu(dividend % divisor); + acc = _mm_xor_si128_emu(modulo, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + if (dividend & 1) + { + const __m128i temp12 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128_emu(temp22, temp22, 0x10); + acc = _mm_xor_si128_emu(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prand, tempb2); + } + else + { + const __m128i tempb3 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + _mm_store_si128_emu(prand, tempb3); + } + break; + } + case 0x10: + { + // a few AES operations + const __m128i *rc = prand; + __m128i tmp; + + __m128i temp1 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + __m128i temp2 = _mm_load_si128_emu(pbuf); + + AES2_EMU(temp1, temp2, 0); + MIX2_EMU(temp1, temp2); + + AES2_EMU(temp1, temp2, 4); + MIX2_EMU(temp1, temp2); + + AES2_EMU(temp1, temp2, 8); + MIX2_EMU(temp1, temp2); + + acc = _mm_xor_si128_emu(temp1, acc); + acc = _mm_xor_si128_emu(temp2, acc); + + const __m128i tempa1 = _mm_load_si128_emu(prand); + const __m128i tempa2 = _mm_mulhrs_epi16_emu(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128_emu(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa3); + _mm_store_si128_emu(prand, tempa4); + break; + } + case 0x14: + { + // we'll just call this one the monkins loop, inspired by Chris + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + __m128i tmp; // used by MIX2 + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + uint64_t aesround = 0; + __m128i onekey; + + do + { + // this is simplified over the original verus_clhash + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128_emu(rc++); + const __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128_emu(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + } + else + { + onekey = _mm_load_si128_emu(rc++); + __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? buftmp : pbuf); + const uint64_t roundidx = aesround++ << 2; + AES2_EMU(onekey, temp2, roundidx); + + MIX2_EMU(onekey, temp2); + + acc = _mm_xor_si128_emu(onekey, acc); + acc = _mm_xor_si128_emu(temp2, acc); + } + } while (rounds--); + + const __m128i tempa1 = _mm_load_si128_emu(prand); + const __m128i tempa2 = _mm_mulhrs_epi16_emu(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128_emu(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa3); + _mm_store_si128_emu(prand, tempa4); + break; + } + case 0x18: + { + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + __m128i onekey; + + do + { + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128_emu(rc++); + const __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128_emu(onekey, temp2); + // cannot be zero here, may be negative + const int32_t divisor = (uint32_t)selector; + const int64_t dividend = _mm_cvtsi128_si64_emu(add1); + const __m128i modulo = _mm_cvtsi32_si128_emu(dividend % divisor); + acc = _mm_xor_si128_emu(modulo, acc); + } + else + { + onekey = _mm_load_si128_emu(rc++); + __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? buftmp : pbuf); + const __m128i add1 = _mm_xor_si128_emu(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + const __m128i clprod2 = _mm_mulhrs_epi16_emu(acc, clprod1); + acc = _mm_xor_si128_emu(clprod2, acc); + } + } while (rounds--); + + const __m128i tempa3 = _mm_load_si128_emu(prandex); + const __m128i tempa4 = _mm_xor_si128_emu(tempa3, acc); + _mm_store_si128_emu(prandex, tempa4); + _mm_store_si128_emu(prand, onekey); + break; + } + case 0x1c: + { + const __m128i temp1 = _mm_load_si128_emu(pbuf); + const __m128i temp2 = _mm_load_si128_emu(prandex); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp2); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp2); + + const __m128i tempa3 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + acc = _mm_xor_si128_emu(tempa3, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, tempa3); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, tempa3); + _mm_store_si128_emu(prandex, tempb2); + break; + } + } + } + return acc; +} + +// verus intermediate hash extra +__m128i __verusclmulwithoutreduction64alignedrepeat_sv2_2_port(__m128i *randomsource, const __m128i buf[4], uint64_t keyMask, __m128i **pMoveScratch) +{ + const __m128i pbuf_copy[4] = {_mm_xor_si128(buf[0],buf[2]), _mm_xor_si128(buf[1],buf[3]), buf[2], buf[3]}; + const __m128i *pbuf; + + // divide key mask by 16 from bytes to __m128i + keyMask >>= 4; + + // the random buffer must have at least 32 16 byte dwords after the keymask to work with this + // algorithm. we take the value from the last element inside the keyMask + 2, as that will never + // be used to xor into the accumulator before it is hashed with other values first + __m128i acc = _mm_load_si128_emu(randomsource + (keyMask + 2)); + + for (int64_t i = 0; i < 32; i++) + { + //std::cout << "LOOP " << i << " acc: " << LEToHex(acc) << std::endl; + + const uint64_t selector = _mm_cvtsi128_si64_emu(acc); + + // get two random locations in the key, which will be mutated and swapped + __m128i *prand = randomsource + ((selector >> 5) & keyMask); + __m128i *prandex = randomsource + ((selector >> 32) & keyMask); + + *pMoveScratch++ = prand; + *pMoveScratch++ = prandex; + + // select random start and order of pbuf processing + pbuf = pbuf_copy + (selector & 3); + + switch (selector & 0x1c) + { + case 0: + { + const __m128i temp1 = _mm_load_si128_emu(prandex); + const __m128i temp2 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prandex, tempb2); + break; + } + case 4: + { + const __m128i temp1 = _mm_load_si128_emu(prand); + const __m128i temp2 = _mm_load_si128_emu(pbuf); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + const __m128i clprod2 = _mm_clmulepi64_si128_emu(temp2, temp2, 0x10); + acc = _mm_xor_si128_emu(clprod2, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + acc = _mm_xor_si128_emu(add12, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prand, tempb2); + break; + } + case 8: + { + const __m128i temp1 = _mm_load_si128_emu(prandex); + const __m128i temp2 = _mm_load_si128_emu(pbuf); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + acc = _mm_xor_si128_emu(add1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + const __m128i temp12 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128_emu(temp22, temp22, 0x10); + acc = _mm_xor_si128_emu(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prandex, tempb2); + break; + } + case 0xc: + { + const __m128i temp1 = _mm_load_si128_emu(prand); + const __m128i temp2 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + + // cannot be zero here + const int32_t divisor = (uint32_t)selector; + + acc = _mm_xor_si128_emu(add1, acc); + + const int64_t dividend = _mm_cvtsi128_si64_emu(acc); + const __m128i modulo = _mm_cvtsi32_si128_emu(dividend % divisor); + acc = _mm_xor_si128_emu(modulo, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp1); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp1); + + if (dividend & 1) + { + const __m128i temp12 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + + const __m128i temp22 = _mm_load_si128_emu(pbuf); + const __m128i add12 = _mm_xor_si128_emu(temp12, temp22); + const __m128i clprod12 = _mm_clmulepi64_si128_emu(add12, add12, 0x10); + acc = _mm_xor_si128_emu(clprod12, acc); + const __m128i clprod22 = _mm_clmulepi64_si128_emu(temp22, temp22, 0x10); + acc = _mm_xor_si128_emu(clprod22, acc); + + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, temp12); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, temp12); + _mm_store_si128_emu(prand, tempb2); + } + else + { + const __m128i tempb3 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa2); + _mm_store_si128_emu(prand, tempb3); + const __m128i tempb4 = _mm_load_si128_emu(pbuf); + acc = _mm_xor_si128_emu(tempb4, acc); + } + break; + } + case 0x10: + { + // a few AES operations + const __m128i *rc = prand; + __m128i tmp; + + __m128i temp1 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + __m128i temp2 = _mm_load_si128_emu(pbuf); + + AES2_EMU(temp1, temp2, 0); + MIX2_EMU(temp1, temp2); + + AES2_EMU(temp1, temp2, 4); + MIX2_EMU(temp1, temp2); + + AES2_EMU(temp1, temp2, 8); + MIX2_EMU(temp1, temp2); + + acc = _mm_xor_si128_emu(temp1, acc); + acc = _mm_xor_si128_emu(temp2, acc); + + const __m128i tempa1 = _mm_load_si128_emu(prand); + const __m128i tempa2 = _mm_mulhrs_epi16_emu(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128_emu(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa3); + _mm_store_si128_emu(prand, tempa4); + break; + } + case 0x14: + { + // we'll just call this one the monkins loop, inspired by Chris + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + __m128i tmp; // used by MIX2 + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + uint64_t aesround = 0; + __m128i onekey; + + do + { + // this is simplified over the original verus_clhash + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128_emu(rc++); + const __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? pbuf : buftmp); + const __m128i add1 = _mm_xor_si128_emu(onekey, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + } + else + { + onekey = _mm_load_si128_emu(rc++); + __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? buftmp : pbuf); + const uint64_t roundidx = aesround++ << 2; + AES2_EMU(onekey, temp2, roundidx); + + MIX2_EMU(onekey, temp2); + + acc = _mm_xor_si128_emu(onekey, acc); + acc = _mm_xor_si128_emu(temp2, acc); + } + } while (rounds--); + + const __m128i tempa1 = _mm_load_si128_emu(prand); + const __m128i tempa2 = _mm_mulhrs_epi16_emu(acc, tempa1); + const __m128i tempa3 = _mm_xor_si128_emu(tempa1, tempa2); + + const __m128i tempa4 = _mm_load_si128_emu(prandex); + _mm_store_si128_emu(prandex, tempa3); + _mm_store_si128_emu(prand, tempa4); + break; + } + case 0x18: + { + const __m128i *buftmp = pbuf - (((selector & 1) << 1) - 1); + + uint64_t rounds = selector >> 61; // loop randomly between 1 and 8 times + __m128i *rc = prand; + __m128i onekey; + + do + { + if (selector & (((uint64_t)0x10000000) << rounds)) + { + onekey = _mm_load_si128_emu(rc++); + const __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? pbuf : buftmp); + onekey = _mm_xor_si128_emu(onekey, temp2); + // cannot be zero here, may be negative + const int32_t divisor = (uint32_t)selector; + const int64_t dividend = _mm_cvtsi128_si64_emu(onekey); + const __m128i modulo = _mm_cvtsi32_si128_emu(dividend % divisor); + acc = _mm_xor_si128_emu(modulo, acc); + } + else + { + onekey = _mm_load_si128_emu(rc++); + __m128i temp2 = _mm_load_si128_emu(rounds & 1 ? buftmp : pbuf); + const __m128i add1 = _mm_xor_si128_emu(onekey, temp2); + onekey = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + const __m128i clprod2 = _mm_mulhrs_epi16_emu(acc, onekey); + acc = _mm_xor_si128_emu(clprod2, acc); + } + } while (rounds--); + + const __m128i tempa3 = _mm_load_si128_emu(prandex); + const __m128i tempa4 = _mm_xor_si128_emu(tempa3, acc); + _mm_store_si128_emu(prandex, onekey); + _mm_store_si128_emu(prand, tempa4); + break; + } + case 0x1c: + { + const __m128i temp1 = _mm_load_si128_emu(pbuf); + const __m128i temp2 = _mm_load_si128_emu(prandex); + const __m128i add1 = _mm_xor_si128_emu(temp1, temp2); + const __m128i clprod1 = _mm_clmulepi64_si128_emu(add1, add1, 0x10); + acc = _mm_xor_si128_emu(clprod1, acc); + + const __m128i tempa1 = _mm_mulhrs_epi16_emu(acc, temp2); + const __m128i tempa2 = _mm_xor_si128_emu(tempa1, temp2); + + const __m128i tempa3 = _mm_load_si128_emu(prand); + _mm_store_si128_emu(prand, tempa2); + + acc = _mm_xor_si128_emu(tempa3, acc); + const __m128i temp4 = _mm_load_si128_emu(pbuf - (((selector & 1) << 1) - 1)); + acc = _mm_xor_si128_emu(temp4,acc); + const __m128i tempb1 = _mm_mulhrs_epi16_emu(acc, tempa3); + const __m128i tempb2 = _mm_xor_si128_emu(tempb1, tempa3); + _mm_store_si128_emu(prandex, tempb2); + break; + } + } + } + return acc; +} + +// hashes 64 bytes only by doing a carryless multiplication and reduction of the repeated 64 byte sequence 16 times, +// returning a 64 bit hash value +uint64_t verusclhash_port(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch) { + __m128i * rs64 = (__m128i *)random; + const __m128i * string = (const __m128i *) buf; + + __m128i acc = __verusclmulwithoutreduction64alignedrepeat_port(rs64, string, keyMask, pMoveScratch); + acc = _mm_xor_si128_emu(acc, lazyLengthHash_port(1024, 64)); + return precompReduction64_port(acc); +} + +// hashes 64 bytes only by doing a carryless multiplication and reduction of the repeated 64 byte sequence 16 times, +// returning a 64 bit hash value +uint64_t verusclhash_sv2_1_port(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch) { + __m128i * rs64 = (__m128i *)random; + const __m128i * string = (const __m128i *) buf; + + __m128i acc = __verusclmulwithoutreduction64alignedrepeat_sv2_1_port(rs64, string, keyMask, pMoveScratch); + acc = _mm_xor_si128_emu(acc, lazyLengthHash_port(1024, 64)); + return precompReduction64_port(acc); +} + +uint64_t verusclhash_sv2_2_port(void * random, const unsigned char buf[64], uint64_t keyMask, __m128i **pMoveScratch) { + __m128i * rs64 = (__m128i *)random; + const __m128i * string = (const __m128i *) buf; + + __m128i acc = __verusclmulwithoutreduction64alignedrepeat_sv2_2_port(rs64, string, keyMask, pMoveScratch); + acc = _mm_xor_si128_emu(acc, lazyLengthHash_port(1024, 64)); + return precompReduction64_port(acc); +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/verus_hash.cpp b/src/Native/libverushash/crypto/verus_hash.cpp new file mode 100644 index 000000000..192636e99 --- /dev/null +++ b/src/Native/libverushash/crypto/verus_hash.cpp @@ -0,0 +1,175 @@ +// (C) 2018 The Verus Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/* +This provides the PoW hash function for Verus, a CPU-optimized hash +function with a Haraka V2 core. Unlike Haraka, which is made for short +inputs only, Verus Hash takes any length of input and produces a 256 +bit output. +*/ +#include +#include "common.h" +#include "verus_hash.h" + +void (*CVerusHash::haraka512Function)(unsigned char *out, const unsigned char *in); + +void CVerusHash::Hash(void *result, const void *data, size_t _len) +{ + unsigned char buf[128]; + unsigned char *bufPtr = buf; + int nextOffset = 64; + uint32_t pos = 0, len = _len; + unsigned char *bufPtr2 = bufPtr + nextOffset; + unsigned char *ptr = (unsigned char *)data; + + // put our last result or zero at beginning of buffer each time + memset(bufPtr, 0, 32); + + // digest up to 32 bytes at a time + for ( ; pos < len; pos += 32) + { + if (len - pos >= 32) + { + memcpy(bufPtr + 32, ptr + pos, 32); + } + else + { + int i = (int)(len - pos); + memcpy(bufPtr + 32, ptr + pos, i); + memset(bufPtr + 32 + i, 0, 32 - i); + } + (*haraka512Function)(bufPtr2, bufPtr); + bufPtr2 = bufPtr; + bufPtr += nextOffset; + nextOffset *= -1; + } + memcpy(result, bufPtr, 32); +}; + +void CVerusHash::init() +{ + if (IsCPUVerusOptimized()) + { + haraka512Function = &haraka512_zero; + } + else + { + haraka512Function = &haraka512_port_zero; + } +} + +CVerusHash &CVerusHash::Write(const unsigned char *data, size_t _len) +{ + unsigned char *tmp; + uint32_t pos, len = _len; + + // digest up to 32 bytes at a time + for ( pos = 0; pos < len; ) + { + uint32_t room = 32 - curPos; + + if (len - pos >= room) + { + memcpy(curBuf + 32 + curPos, data + pos, room); + (*haraka512Function)(result, curBuf); + tmp = curBuf; + curBuf = result; + result = tmp; + pos += room; + curPos = 0; + } + else + { + memcpy(curBuf + 32 + curPos, data + pos, len - pos); + curPos += len - pos; + pos = len; + } + } + return *this; +} + +void (*CVerusHashV2::haraka512Function)(unsigned char *out, const unsigned char *in); +void (*CVerusHashV2::haraka512KeyedFunction)(unsigned char *out, const unsigned char *in, const u128 *rc); +void (*CVerusHashV2::haraka256Function)(unsigned char *out, const unsigned char *in); + +void CVerusHashV2::init() +{ + if (IsCPUVerusOptimized()) + { + load_constants(); + haraka512Function = &haraka512; + haraka512KeyedFunction = &haraka512_keyed; + haraka256Function = &haraka256; + } + else + { + // load the haraka constants + load_constants_port(); + haraka512Function = &haraka512_port; + haraka512KeyedFunction = &haraka512_port_keyed; + haraka256Function = &haraka256_port; + } +} + +void CVerusHashV2::Hash(void *result, const void *data, size_t _len) +{ + unsigned char buf[128]; + unsigned char *bufPtr = buf; + int len = _len, pos = 0, nextOffset = 64; + unsigned char *bufPtr2 = bufPtr + nextOffset; + unsigned char *ptr = (unsigned char *)data; + + // put our last result or zero at beginning of buffer each time + memset(bufPtr, 0, 32); + + // digest up to 32 bytes at a time + for ( ; pos < len; pos += 32) + { + if (len - pos >= 32) + { + memcpy(bufPtr + 32, ptr + pos, 32); + } + else + { + int i = (int)(len - pos); + memcpy(bufPtr + 32, ptr + pos, i); + memset(bufPtr + 32 + i, 0, 32 - i); + } + (*haraka512Function)(bufPtr2, bufPtr); + bufPtr2 = bufPtr; + bufPtr += nextOffset; + nextOffset *= -1; + } + memcpy(result, bufPtr, 32); +}; + +CVerusHashV2 &CVerusHashV2::Write(const unsigned char *data, size_t _len) +{ + unsigned char *tmp; + int len = _len; + + // digest up to 32 bytes at a time + for (int pos = 0; pos < len; ) + { + int room = 32 - curPos; + + if (len - pos >= room) + { + memcpy(curBuf + 32 + curPos, data + pos, room); + (*haraka512Function)(result, curBuf); + tmp = curBuf; + curBuf = result; + result = tmp; + pos += room; + curPos = 0; + } + else + { + memcpy(curBuf + 32 + curPos, data + pos, len - pos); + curPos += len - pos; + pos = len; + } + } + return *this; +} \ No newline at end of file diff --git a/src/Native/libverushash/crypto/verus_hash.h b/src/Native/libverushash/crypto/verus_hash.h new file mode 100644 index 000000000..3a2db8af4 --- /dev/null +++ b/src/Native/libverushash/crypto/verus_hash.h @@ -0,0 +1,235 @@ +// (C) 2018 Michael Toutonghi +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/* +This provides the PoW hash function for Verus, enabling CPU mining. +*/ +#ifndef VERUS_HASH_H_ +#define VERUS_HASH_H_ + +// verbose output when defined +//#define VERUSHASHDEBUG 1 + +#include +#include + +#include "uint256.h" +#include "verus_clhash.h" + +extern "C" +{ +#include "haraka.h" +#include "haraka_portable.h" +} + +class CVerusHash +{ + public: + static void Hash(void *result, const void *data, size_t len); + static void (*haraka512Function)(unsigned char *out, const unsigned char *in); + + static void init(); + + CVerusHash() { } + + CVerusHash &Write(const unsigned char *data, size_t len); + + CVerusHash &Reset() + { + curBuf = buf1; + result = buf2; + curPos = 0; + std::fill(buf1, buf1 + sizeof(buf1), 0); + return *this; + } + + int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } + void ClearExtra() + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + } + } + void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } + + void Finalize(unsigned char hash[32]) + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + (*haraka512Function)(hash, curBuf); + } + else + std::memcpy(hash, curBuf, 32); + } + + private: + // only buf1, the first source, needs to be zero initialized + unsigned char buf1[64] = {0}, buf2[64]; + unsigned char *curBuf = buf1, *result = buf2; + size_t curPos = 0; +}; + +class CVerusHashV2 +{ + public: + static void Hash(void *result, const void *data, size_t len); + static void (*haraka512Function)(unsigned char *out, const unsigned char *in); + static void (*haraka512KeyedFunction)(unsigned char *out, const unsigned char *in, const u128 *rc); + static void (*haraka256Function)(unsigned char *out, const unsigned char *in); + + static void init(); + + verusclhasher vclh; + + CVerusHashV2(int solutionVerusion=SOLUTION_VERUSHHASH_V2) : vclh(VERUSKEYSIZE, solutionVerusion) { + // we must have allocated key space, or can't run + if (!verusclhasher_key.get()) + { + printf("ERROR: failed to allocate hash buffer - terminating\n"); + assert(false); + } + } + + CVerusHashV2 &Write(const unsigned char *data, size_t len); + + inline CVerusHashV2 &Reset() + { + curBuf = buf1; + result = buf2; + curPos = 0; + std::fill(buf1, buf1 + sizeof(buf1), 0); + return *this; + } + + inline int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } + inline void ClearExtra() + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + } + } + + template + inline void FillExtra(const T *_data) + { + unsigned char *data = (unsigned char *)_data; + int pos = curPos; + int left = 32 - pos; + do + { + int len = left > (int)sizeof(T) ? sizeof(T) : left; + std::memcpy(curBuf + 32 + pos, data, len); + pos += len; + left -= len; + } while (left > 0); + } + inline void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } + inline void ExtraHashKeyed(unsigned char hash[32], u128 *key) { (*haraka512KeyedFunction)(hash, curBuf, key); } + + void Finalize(unsigned char hash[32]) + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + (*haraka512Function)(hash, curBuf); + } + else + std::memcpy(hash, curBuf, 32); + } + + // chains Haraka256 from 32 bytes to fill the key + static u128 *GenNewCLKey(unsigned char *seedBytes32) + { + unsigned char *key = (unsigned char *)verusclhasher_key.get(); + verusclhash_descr *pdesc = (verusclhash_descr *)verusclhasher_descr.get(); + int size = pdesc->keySizeInBytes; + int refreshsize = verusclhasher::keymask(size) + 1; + // skip keygen if it is the current key + if (pdesc->seed != *((uint256 *)seedBytes32)) + { + // generate a new key by chain hashing with Haraka256 from the last curbuf + int n256blks = size >> 5; + int nbytesExtra = size & 0x1f; + unsigned char *pkey = key; + unsigned char *psrc = seedBytes32; + for (int i = 0; i < n256blks; i++) + { + (*haraka256Function)(pkey, psrc); + psrc = pkey; + pkey += 32; + } + if (nbytesExtra) + { + unsigned char buf[32]; + (*haraka256Function)(buf, psrc); + memcpy(pkey, buf, nbytesExtra); + } + pdesc->seed = *((uint256 *)seedBytes32); + memcpy(key + size, key, refreshsize); + } + else + { + memcpy(key, key + size, refreshsize); + } + + memset((unsigned char *)key + (size + refreshsize), 0, size - refreshsize); + return (u128 *)key; + } + + inline uint64_t IntermediateTo128Offset(uint64_t intermediate) + { + // the mask is where we wrap + uint64_t mask = vclh.keyMask >> 4; + return intermediate & mask; + } + + void Finalize2b(unsigned char hash[32]) + { + // fill buffer to the end with the beginning of it to prevent any foreknowledge of + // bits that may contain zero + FillExtra((u128 *)curBuf); + +#ifdef VERUSHASHDEBUG + uint256 *bhalf1 = (uint256 *)curBuf; + uint256 *bhalf2 = bhalf1 + 1; + printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str()); +#endif + + // gen new key with what is last in buffer + u128 *key = GenNewCLKey(curBuf); + + // run verusclhash on the buffer + uint64_t intermediate = vclh(curBuf, key); + + // fill buffer to the end with the result + FillExtra(&intermediate); + +#ifdef VERUSHASHDEBUG + printf("intermediate %lx\n", intermediate); + printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str()); + bhalf1 = (uint256 *)key; + bhalf2 = bhalf1 + ((vclh.keyMask + 1) >> 5); + printf(" Key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str()); +#endif + + // get the final hash with a mutated dynamic key for each hash result + (*haraka512KeyedFunction)(hash, curBuf, key + IntermediateTo128Offset(intermediate)); + } + + inline unsigned char *CurBuffer() + { + return curBuf; + } + + private: + // only buf1, the first source, needs to be zero initialized + alignas(32) unsigned char buf1[64] = {0}, buf2[64]; + unsigned char *curBuf = buf1, *result = buf2; + size_t curPos = 0; +}; + +#endif \ No newline at end of file diff --git a/src/Native/libverushash/exports.cpp b/src/Native/libverushash/exports.cpp new file mode 100644 index 000000000..ddd9c31e6 --- /dev/null +++ b/src/Native/libverushash/exports.cpp @@ -0,0 +1,49 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "verushashverify.h" + +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif + +extern "C" MODULE_API void verushash2b2_export(char* input, char* output, int input_length) +{ + verushash2b2(input, output, input_length); +} + +extern "C" MODULE_API void verushash2b1_export(char* input, char* output, int input_length) +{ + verushash2b1(input, output, input_length); +} + +extern "C" MODULE_API void verushash2b_export(char* input, char* output, int input_length) +{ + verushash2b(input, output, input_length); +} + +extern "C" MODULE_API void verushash2_export(char* input, char* output, int input_length) +{ + verushash2(input, output, input_length); +} + +extern "C" MODULE_API void verushash_export(char* input, char* output, int input_length) +{ + verushash(input, output, input_length); +} \ No newline at end of file diff --git a/src/Native/libverushash/libverushash.sln b/src/Native/libverushash/libverushash.sln new file mode 100644 index 000000000..6c300648a --- /dev/null +++ b/src/Native/libverushash/libverushash.sln @@ -0,0 +1,31 @@ + +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}") = "libverushash", "libverushash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libverushash/libverushash.vcxproj b/src/Native/libverushash/libverushash.vcxproj new file mode 100644 index 000000000..ae3c444aa --- /dev/null +++ b/src/Native/libverushash/libverushash.vcxproj @@ -0,0 +1,203 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libverushash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libmultihash\windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(ProjectDir)..\libmultihash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libmultihash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libverushash/sodium.h b/src/Native/libverushash/sodium.h new file mode 100644 index 000000000..6e5aa8736 --- /dev/null +++ b/src/Native/libverushash/sodium.h @@ -0,0 +1,69 @@ + +#ifndef sodium_H +#define sodium_H + +#include "../libmultihash/windows/include/libsodium/sodium/version.h" + +#include "../libmultihash/windows/include/libsodium/sodium/core.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_aead_aes256gcm.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_aead_chacha20poly1305.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_aead_xchacha20poly1305.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_auth.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_auth_hmacsha256.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_auth_hmacsha512.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_auth_hmacsha512256.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_box.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_box_curve25519xsalsa20poly1305.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_core_hsalsa20.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_core_hchacha20.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_core_salsa20.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_core_salsa2012.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_core_salsa208.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_generichash.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_generichash_blake2b.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_hash.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_hash_sha256.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_hash_sha512.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_kdf.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_kdf_blake2b.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_kx.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_onetimeauth.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_onetimeauth_poly1305.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_pwhash.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_pwhash_argon2i.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_scalarmult.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_scalarmult_curve25519.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_secretbox.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_secretbox_xsalsa20poly1305.h" +//#include "../libmultihash/windows/include/libsodium/sodium/crypto_secretstream_xchacha20poly1305.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_shorthash.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_shorthash_siphash24.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_sign.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_sign_ed25519.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_stream.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_stream_chacha20.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_stream_salsa20.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_stream_xsalsa20.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_verify_16.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_verify_32.h" +#include "../libmultihash/windows/include/libsodium/sodium/crypto_verify_64.h" +#include "../libmultihash/windows/include/libsodium/sodium/randombytes.h" +//#include "../libmultihash/windows/include/libsodium/sodium/randombytes_internal_random.h" +#include "../libmultihash/windows/include/libsodium/sodium/randombytes_sysrandom.h" +#include "../libmultihash/windows/include/libsodium/sodium/runtime.h" +#include "../libmultihash/windows/include/libsodium/sodium/utils.h" + +#ifndef SODIUM_LIBRARY_MINIMAL +# include "../libmultihash/windows/include/libsodium/sodium/crypto_box_curve25519xchacha20poly1305.h" +//# include "../libmultihash/windows/include/libsodium/sodium/crypto_core_ed25519.h" +//# include "../libmultihash/windows/include/libsodium/sodium/crypto_core_ristretto255.h" +//# include "../libmultihash/windows/include/libsodium/sodium/crypto_scalarmult_ed25519.h" +//# include "../libmultihash/windows/include/libsodium/sodium/crypto_scalarmult_ristretto255.h" +# include "../libmultihash/windows/include/libsodium/sodium/crypto_secretbox_xchacha20poly1305.h" +# include "../libmultihash/windows/include/libsodium/sodium/crypto_pwhash_scryptsalsa208sha256.h" +# include "../libmultihash/windows/include/libsodium/sodium/crypto_stream_salsa2012.h" +# include "../libmultihash/windows/include/libsodium/sodium/crypto_stream_salsa208.h" +# include "../libmultihash/windows/include/libsodium/sodium/crypto_stream_xchacha20.h" +#endif + +#endif diff --git a/src/Native/libverushash/verushashverify.cpp b/src/Native/libverushash/verushashverify.cpp new file mode 100644 index 000000000..1d9fdec72 --- /dev/null +++ b/src/Native/libverushash/verushashverify.cpp @@ -0,0 +1,125 @@ +#include "verushashverify.h" +#include + +#include "crypto/common.h" +#include "crypto/verus_hash.h" + +const unsigned char BLAKE2Bpersonal[crypto_generichash_blake2b_PERSONALBYTES] = { 'V','e','r','u','s','D','e','f','a','u','l','t','H','a','s','h' }; +uint256 blake2b_hash(unsigned char* data, unsigned long long length) +{ + const unsigned char* personal = BLAKE2Bpersonal; + crypto_generichash_blake2b_state state; + uint256 result; + if (crypto_generichash_blake2b_init_salt_personal( + &state, + NULL, 0, // No key. + 32, + NULL, // No salt. + personal) == 0) { + crypto_generichash_blake2b_update(&state, data, length); + if (crypto_generichash_blake2b_final(&state, reinterpret_cast(&result), crypto_generichash_blake2b_BYTES) == 0) { + return result; + } + } + result.SetNull(); + return result; +} + +void verushash2b2(char* input, char* output, int input_len) +{ + //CVerusHashV2* vh2b2; + CVerusHashV2::init(); + + // detect pbaas, validate and clear non-canonical data if needed + char* solution = (input + 140 + 3); + unsigned int sol_ver = ((solution[0]) + (solution[1] << 8) + (solution[2] << 16) + (solution[3] << 24)); + if (sol_ver > 6) { + //const uint8_t descrBits = solution[4]; + const uint8_t numPBaaSHeaders = solution[5]; + //const uint16_t extraSpace = solution[6] | ((uint16_t)(solution[7]) << 8); + const uint32_t soln_header_size = 4 + 1 + 1 + 2 + 32 + 32; // version, descr, numPBaas, extraSpace, hashPrevMMRroot, hashBlockMMRroot + const uint32_t soln_pbaas_cid_size = 20; // hash160 + const uint32_t soln_pbaas_prehash_sz = 32; // pre header hash blake2b + // if pbaas headers present + if (numPBaaSHeaders > 0) { + unsigned char preHeader[32 + 32 + 32 + 32 + 4 + 32 + 32] = { 0, }; + + // copy non-canonical items from block header + memcpy(&preHeader[0], input + 4, 32); // hashPrevBlock + memcpy(&preHeader[32], input + 4 + 32, 32); // hashMerkleRoot + memcpy(&preHeader[64], input + 4 + 32 + 32, 32); // hashFinalSaplingRoot + memcpy(&preHeader[96], input + 4 + 32 + 32 + 32 + 4 + 4, 32); // nNonce (if nonce changes must update preHeaderHash in solution) + memcpy(&preHeader[128], input + 4 + 32 + 32 + 32 + 4, 4); // nbits + memcpy(&preHeader[132], solution + 8, 32 + 32); // hashPrevMMRRoot, hashPrevMMRRoot + + // detect if merged mining is present and clear non-canonical data (if needed) + int matched_zeros = 0; + for (int i = 0; i < sizeof(preHeader); i++) { + if (preHeader[i] == 0) { matched_zeros++; } + } + + // if the data has already been cleared of non-canonical data, just continue along + if (matched_zeros != sizeof(preHeader)) { + // detect merged mining by looking for preHeaderHash (blake2b) in first pbaas chain definition + int matched_hashes = 0; + uint256 preHeaderHash = blake2b_hash(&preHeader[0], sizeof(preHeader)); + if (!preHeaderHash.IsNull()) { + if (memcmp((unsigned char*)&preHeaderHash, + &solution[soln_header_size + soln_pbaas_cid_size], + soln_pbaas_prehash_sz) == 0) { + matched_hashes++; + } + } + // clear non-canonical data for pbaas merge mining + if (matched_hashes > 0) { + memset(input + 4, 0, 32 + 32 + 32); // hashPrevBlock, hashMerkleRoot, hashFinalSaplingRoot + memset(input + 4 + 32 + 32 + 32 + 4, 0, 4); // nBits + memset(input + 4 + 32 + 32 + 32 + 4 + 4, 0, 32); // nNonce + memset(solution + 8, 0, 32 + 32); // hashPrevMMRRoot, hashBlockMMRRoot + //printf("info: merged mining %d chains, clearing non-canonical data on hash found\n", numPBaaSHeaders); + } else { + // invalid share, pbaas activated must be pbaas mining capatible + memset(output, 0xff, 32); + return; + } + } else { + //printf("info: merged mining %d chains, non-canonical data pre-cleared\n", numPBaaSHeaders); + } + } + } + + CVerusHashV2* vh2b2 = new CVerusHashV2(SOLUTION_VERUSHHASH_V2_2); + vh2b2->Reset(); + vh2b2->Write((const unsigned char *)input, input_len); + vh2b2->Finalize2b((unsigned char *)output); +} + +void verushash2b1(char* input, char* output, int input_len) +{ + //CVerusHashV2* vh2b1; + CVerusHashV2::init(); + CVerusHashV2* vh2b1 = new CVerusHashV2(SOLUTION_VERUSHHASH_V2_1); + vh2b1->Reset(); + vh2b1->Write((const unsigned char *)input, input_len); + vh2b1->Finalize2b((unsigned char *)output); +} + +void verushash2b(char* input, char* output, int input_len) +{ + //CVerusHashV2* vh2; + CVerusHashV2::init(); + CVerusHashV2* vh2 = new CVerusHashV2(SOLUTION_VERUSHHASH_V2); + vh2->Reset(); + vh2->Write((const unsigned char *)input, input_len); + vh2->Finalize2b((unsigned char *)output); +} + +void verushash2(char* input, char* output, int input_len) +{ + return CVerusHashV2::Hash(output, input, input_len); +} + +void verushash(char* input, char* output, int input_len) +{ + return CVerusHash::Hash(output, input, input_len); +} \ No newline at end of file diff --git a/src/Native/libverushash/verushashverify.h b/src/Native/libverushash/verushashverify.h new file mode 100644 index 000000000..47267fc25 --- /dev/null +++ b/src/Native/libverushash/verushashverify.h @@ -0,0 +1,20 @@ +#ifndef VERUSHASHVERIFY_H +#define VERUSHASHVERIFY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void verushash2b2(char* input, char* output, int input_len); +void verushash2b1(char* input, char* output, int input_len); +void verushash2b(char* input, char* output, int input_len); +void verushash2(char* input, char* output, int input_len); +void verushash(char* input, char* output, int input_len); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file From 99d37775ef8e82a7a950e774a4a1120b9a239d0a Mon Sep 17 00:00:00 2001 From: ceedii Date: Mon, 5 Jun 2023 01:21:40 +0000 Subject: [PATCH 09/38] Add support for MinotaurX Add support for Beam Add support for Veruscoin (PBaaS) --- build.backup/config.json | 827 --------------------------------------- 1 file changed, 827 deletions(-) delete mode 100644 build.backup/config.json diff --git a/build.backup/config.json b/build.backup/config.json deleted file mode 100644 index 0ce9d8c94..000000000 --- a/build.backup/config.json +++ /dev/null @@ -1,827 +0,0 @@ -{ - "logging": { - "level": "debug", - "enableConsoleLog": true, - "enableConsoleColors": true, - "logFile": "miningcore.log", - "apiLogFile": "api.log", - "logBaseDirectory": "/home/ceedii/miningcore/build/", - "perPoolLogFile": true - }, - "banning": { - "manager": "Integrated", - "banOnJunkReceive": true, - "banOnInvalidShares": false - }, - "notifications": { - "enabled": false, - "email": { - "host": "localhost", - "port": 25, - "user": "", - "password": "", - "fromAddress": "noreply@mining-pool.cedric-crispin.local", - "fromName": "[Mining Pool - Cedric CRISPIN - Developpement]" - }, - "admin": { - "enabled": false, - "emailAddress": "cedric.crispin@gmail.com", - "notifyBlockFound": true - } - }, - "persistence": { - "postgres": { - "host": "127.0.0.1", - "port": 5432, - "user": "mining_pool_cedric_crispin_com", - "password": "hzFWPsCJ9crp9Jwqfgds3NkwhRCPcrrfNxc", - "database": "mining_pool_cedric_crispin_com", - "commandTimeout": 600 - } - }, - "equihashMaxThreads": 2, - "paymentProcessing": { - "enabled": true, - "interval": 600, - "shareRecoveryFile": "recovered-shares.txt" - }, - "api": { - "enabled": true, - "listenAddress": "0.0.0.0", - "port": 4000, - "metricsIpWhitelist": [], - "rateLimiting": { - "disabled": false, - "rules": [ - { - "Endpoint": "*", - "Period": "1s", - "Limit": 30 - } - ], - "ipWhitelist": ["192.168.1.7"] - } - }, - "pools": [ - { - "id": "vtc1", - "enabled": false, - "coin": "vertcoin", - "vertHashDataFile": "/home/ceedii/.vertcoin/testnet3/verthash.dat", - "address": "X1n3Gf4QHwM8XLbE63iRJo3HcWzE34bjmk", - "rewardRecipients": [ - { - "type": "op", - "address": "X1n3Gf4QHwM8XLbE63iRJo3HcWzE34bjmk", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 250, - "jobRebroadcastTimeout": 3, - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "3334": { - "listenAddress": "0.0.0.0", - "difficulty": 0.0005, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.0005, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "3335": { - "listenAddress": "0.0.0.0", - "difficulty": 0.0005, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.0005, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 15888, - "user": "vtc1qsjurynfa3uzsw2wctuhn4kzzh27adv3c5zg0wu", - "password": "98bct78hKopZYxWZVWRcbtb85IKB6yxN9H6qAH_09oU=" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 1, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - }, - { - "id": "xmr1", - "enabled": false, - "coin": "monero", - "randomXRealm": "xmr1", - "randomXVmCount": 1, - "randomXFlagsAdd": "RANDOMX_FLAG_FULL_MEM", - "address": "9w2B8t5aGdKCZTaGsUFre32FA7Z3hz2X2KzUvA3mVmoZFCK3HzaFQjEK9wMm1LAtR2378jij9uAPjM4UChux3GuZFd3aGqu", - "rewardRecipients": [ - { - "type": "op", - "address": "9w2B8t5aGdKCZTaGsUFre32FA7Z3hz2X2KzUvA3mVmoZFCK3HzaFQjEK9wMm1LAtR2378jij9uAPjM4UChux3GuZFd3aGqu", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 250, - "jobRebroadcastTimeout": 3, - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "3344": { - "listenAddress": "0.0.0.0", - "difficulty": 7500, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 1000, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "3345": { - "listenAddress": "0.0.0.0", - "difficulty": 7500, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 1000, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 28081, - "user": null, - "password": null - }, - { - "host": "127.0.0.1", - "port": 28083, - "user": null, - "password": null, - "category": "wallet" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 0.001, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - }, - { - "id": "erg1", - "enabled": false, - "coin": "ergo", - "address": "3WzFWwWi6E7TvnXvZEeNUTaieTx4PUckVPhnL6PED5wjr8vWSdo9", - "rewardRecipients": [ - { - "type": "op", - "address": "3WzFWwWi6E7TvnXvZEeNUTaieTx4PUckVPhnL6PED5wjr8vWSdo9", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 250, - "jobRebroadcastTimeout": 3, - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "3354": { - "listenAddress": "0.0.0.0", - "difficulty": 1, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 1, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "3355": { - "listenAddress": "0.0.0.0", - "difficulty": 1, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 1, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 9052, - "user": null, - "password": null, - "apiKey": "TXfjTjjH7L9bthrHdtx3xmpNnxNCNgNJ9Hv" - } - ], - "paymentProcessing": { - "enabled": true, - "walletPassword": "z=f?!3!-wx^tWrF!fHjX", - "minimumPayment": 0.01, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - }, - { - "id": "ccx1", - "enabled": false, - "coin": "conceal", - "networkTypeOverride": "testnet", - "cryptonightMaxThreads": 1, - "address": "ccx7BRXk4eubahkPNe4mmZ1PYwigPmqGT5ciBWib39aQQjWctY6vzA7RuBBkcoSKxEVBQArdvJi5YhEHRY29sSpS9EiD5c2nW5", - "rewardRecipients": [ - { - "type": "op", - "address": "ccx7BRXk4eubahkPNe4mmZ1PYwigPmqGT5ciBWib39aQQjWctY6vzA7RuBBkcoSKxEVBQArdvJi5YhEHRY29sSpS9EiD5c2nW5", - "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": 5000, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 2500, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "3365": { - "listenAddress": "0.0.0.0", - "difficulty": 5000, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 2500, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 16600, - "user": null, - "password": null - }, - { - "host": "127.0.0.1", - "port": 8770, - "user": null, - "password": null, - "category": "wallet" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 0.1, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - }, - { - "id": "rxd1", - "enabled": false, - "coin": "radiant", - "address": "ms4rYFqGfot5gz9hZ6FYNaGnYiFh3sXVCT", - "rewardRecipients": [ - { - "type": "op", - "address": "ms4rYFqGfot5gz9hZ6FYNaGnYiFh3sXVCT", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 250, - "jobRebroadcastTimeout": 3, - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "3374": { - "listenAddress": "0.0.0.0", - "difficulty": 0.5, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.5, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "3375": { - "listenAddress": "0.0.0.0", - "difficulty": 0.5, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.5, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 17332, - "user": "ms4rYFqGfot5gz9hZ6FYNaGnYiFh3sXVCT", - "password": "qT-CvLnXDmOSw5sckZghZG0ezX7-Oz3jKUW33hVvP6A=" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 1, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - }, - { - "id": "ubq1", - "enabled": false, - "coin": "ubiq", - "address": "0x6101Ee22AB2cd3907E5CA0b70EF12A2afE842A56", - "rewardRecipients": [ - { - "type": "op", - "address": "0x6101Ee22AB2cd3907E5CA0b70EF12A2afE842A56", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 120, - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "3384": { - "listenAddress": "0.0.0.0", - "difficulty": 0.1, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.1, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "3385": { - "listenAddress": "0.0.0.0", - "difficulty": 0.1, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.1, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "chainTypeOverride": "Ubiq", - "dagDir": "/home/ceedii/.ubqhash/", - "daemons": [ - { - "host": "127.0.0.1", - "port": 8588, - "portWs": 8589, - "user": "", - "password": "" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 0.001, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - }, - "gas": 21000, - "maxFeePerGas": 80000000000, - "BlockSearchOffset": 100, - "keepUncles": false, - "keepTransactionFees": false - } - }, - { - "id": "etc1", - "enabled": false, - "coin": "ethereumclassic", - "address": "0x421Afb2ce225D3A2d3DD6e63Fe57E124B40e20Af", - "rewardRecipients": [ - { - "type": "op", - "address": "0x421Afb2ce225D3A2d3DD6e63Fe57E124B40e20Af", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 120, - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "3394": { - "listenAddress": "0.0.0.0", - "difficulty": 0.1, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.1, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "3395": { - "listenAddress": "0.0.0.0", - "difficulty": 0.1, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.1, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "chainTypeOverride": "Mordor", - "dagDir": "/home/ceedii/.etchash/", - "daemons": [ - { - "host": "127.0.0.1", - "port": 8545, - "portWs": 8546, - "user": "", - "password": "" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 0.001, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - }, - "gas": 21000, - "maxFeePerGas": 50000000000, - "BlockSearchOffset": 100, - "keepUncles": false, - "keepTransactionFees": false - } - }, - { - "id": "plsr1", - "enabled": false, - "coin": "pulsar", - "address": "PKeqLKLnPv7ZWmuBxnjHp9G9b4S3wZQZoN", - "rewardRecipients": [ - { - "type": "op", - "address": "PKeqLKLnPv7ZWmuBxnjHp9G9b4S3wZQZoN", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 120, - "jobRebroadcastTimeout": 3, - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "4004": { - "listenAddress": "0.0.0.0", - "difficulty": 0.0001, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.0001, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "4005": { - "listenAddress": "0.0.0.0", - "difficulty": 0.0001, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 0.0001, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 5996, - "user": "PKeqLKLnPv7ZWmuBxnjHp9G9b4S3wZQZoN", - "password": "kP1-W4R8dt7xU6UWr4ns1w45CSoFQUfjhQj0IIuEJ60=" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 0.001, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - }, - { - "id": "beam1", - "enabled": false, - "coin": "beam", - "maxActiveJobs": 4, - "address": "2b53f3e23bd471de6b502575f6ef6f65fee55ac85baed63f307324f9cf78d0c4ebe", - "rewardRecipients": [ - { - "type": "op", - "address": "2b53f3e23bd471de6b502575f6ef6f65fee55ac85baed63f307324f9cf78d0c4ebe", - "percentage": 0.1 - } - ], - "clientConnectionTimeout": 600, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "4014": { - "listenAddress": "0.0.0.0", - "difficulty": 700, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 200, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - }, - "4015": { - "listenAddress": "0.0.0.0", - "difficulty": 700, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 200, - "maxDiff": null, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 500 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 11001, - "user": null, - "password": null, - "apiKey": "4Nsmr4xftwXpWcg" - }, - { - "host": "127.0.0.1", - "port": 10000, - "user": null, - "password": null, - "category": "wallet" - }, - { - "host": "127.0.0.1", - "port": 10002, - "user": null, - "password": null, - "category": "explorer" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 1, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - }, - { - "id": "vrsc1", - "enabled": true, - "coin": "veruscoin", - "address": "RGk5aoCpv9Yqajnf7HDwdDUgPhRVvVGBVe", - "z-address": "zs1eqnvc3nfd6wz5m65n7ygc9pkqzpx8zwzlz6epx8rvsvdu88k9anapu5gcg8ekq2fzsl3654fzc2", - "GBTArgs": [{ - "capabilities": [ - "coinbasetxn", - "workid", - "coinbase/append" - ] - }], - "rewardRecipients": [ - { - "type": "op", - "address": "RGk5aoCpv9Yqajnf7HDwdDUgPhRVvVGBVe", - "percentage": 0.1 - } - ], - "blockRefreshInterval": 0, - "jobRebroadcastTimeout": 0, - "clientConnectionTimeout": 2400, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 50, - "checkThreshold": 50 - }, - "ports": { - "4024": { - "listenAddress": "0.0.0.0", - "difficulty": 256, - "tls": false, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 256, - "maxDiff": 1048576000, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 512 - } - }, - "4025": { - "listenAddress": "0.0.0.0", - "difficulty": 256, - "tls": true, - "tlsPfxFile": "/etc/apache2/ssl/www.cedric-crispin.local.pfx", - "tlsPfxPassword": "f`k+4b4{Fbr?++?{`@M[", - "varDiff": { - "minDiff": 256, - "maxDiff": 1048576000, - "targetTime": 15, - "retargetTime": 90, - "variancePercent": 30, - "maxDelta": 512 - } - } - }, - "daemons": [ - { - "host": "127.0.0.1", - "port": 17771, - "user": "RGk5aoCpv9Yqajnf7HDwdDUgPhRVvVGBVe", - "password": "qsnrdbq7KdWwNctKq7jkbjmvftPnXbTRjqn", - "ZmqBlockNotifySocket": "tcp://127.0.0.1:17772", - "ZmqBlockNotifyTopic": "rawblock" - } - ], - "paymentProcessing": { - "enabled": true, - "minimumPayment": 0.0001, - "payoutScheme": "PPLNS", - "payoutSchemeConfig": { - "factor": 0.5 - } - } - } - ] -} \ No newline at end of file From 65fe338bf6a7b53f746e27bbb438a3531de7c898 Mon Sep 17 00:00:00 2001 From: ceedii Date: Wed, 21 Jun 2023 03:52:23 +0000 Subject: [PATCH 10/38] Add support for Ravencoin (RVN) & Firo (FIRO) Optimizations for the ethash family: allow use of full DAG and light cache DAG Little improvements for Verus (VRSC) --- examples/callisto_pool.json | 1 - examples/ethereum_pool.json | 1 - examples/ethereumclassic_pool.json | 1 - examples/firo_pool.json | 126 ++++ examples/ravencoin_pool.json | 124 +++ examples/ubiq_pool.json | 1 - examples/veruscoin_pool.json | 7 +- .../Benchmarks/BenchmarkRunner.cs | 18 +- .../Benchmarks/Crypto/EthashBenchmarks.cs | 39 + src/Miningcore.Tests/Crypto/EthashTests.cs | 81 ++ src/Miningcore/AutofacModule.cs | 22 +- .../Blockchain/Conceal/ConcealJobManager.cs | 28 +- .../Cryptonote/CryptonoteJobManager.cs | 28 +- .../Blockchain/Equihash/EquihashPool.cs | 2 +- .../Blockchain/Ethereum/EthereumConstants.cs | 2 - .../Blockchain/Ethereum/EthereumJob.cs | 160 +--- .../Blockchain/Ethereum/EthereumJobManager.cs | 196 ++--- .../Blockchain/Progpow/Custom/Firo/FiroJob.cs | 205 +++++ .../Blockchain/Progpow/ProgpowConstants.cs | 22 + .../Progpow/ProgpowExtraNonceProvider.cs | 15 + .../Blockchain/Progpow/ProgpowJob.cs | 297 ++++++++ .../Blockchain/Progpow/ProgpowJobManager.cs | 320 ++++++++ .../Blockchain/Progpow/ProgpowPool.cs | 422 +++++++++++ .../Progpow/ProgpowStratumMethods.cs | 39 + .../Blockchain/Progpow/ProgpowUtils.cs | 51 ++ .../Progpow/ProgpowWorkerContext.cs | 36 + .../Blockchain/Progpow/ProgpowWorkerJob.cs | 65 ++ src/Miningcore/Configuration/ClusterConfig.cs | 17 + .../Configuration/ClusterConfigExtensions.cs | 38 +- .../Crypto/Hashing/Etchash/DagEtchash.cs | 143 ---- .../Crypto/Hashing/Etchash/EtchashFull.cs | 94 --- .../Crypto/Hashing/Ethash/Abstractions.cs | 15 + src/Miningcore/Crypto/Hashing/Ethash/Dag.cs | 141 ---- .../Crypto/Hashing/Ethash/Etchash/Cache.cs | 170 +++++ .../Hashing/Ethash/Etchash/EtchashLight.cs | 96 +++ .../Crypto/Hashing/Ethash/Ethash/Cache.cs | 169 +++++ .../Ethash/EthashLight.cs} | 46 +- .../Crypto/Hashing/Ethash/EthashFactory.cs | 25 + .../Crypto/Hashing/Ethash/Ubqhash/Cache.cs | 166 +++++ .../UbqhashLight.cs} | 46 +- .../Crypto/Hashing/Progpow/Abstractions.cs | 16 + .../Crypto/Hashing/Progpow/Firopow/Cache.cs | 96 +++ .../Hashing/Progpow/Firopow/FiropowLight.cs | 87 +++ .../Crypto/Hashing/Progpow/Kawpow/Cache.cs | 96 +++ .../Hashing/Progpow/Kawpow/KawpowLight.cs | 87 +++ .../Crypto/Hashing/Progpow/ProgpowFactory.cs | 25 + .../Crypto/Hashing/Ubqhash/DagUbqhash.cs | 141 ---- src/Miningcore/Native/EtcHash.cs | 6 +- src/Miningcore/Native/FiroPow.cs | 37 + src/Miningcore/Native/KawPow.cs | 21 +- src/Miningcore/Payments/PayoutManager.cs | 3 + src/Miningcore/Program.cs | 12 +- src/Miningcore/build-libs-linux.sh | 2 + src/Miningcore/coins.json | 81 +- src/Native/libetchash/ethash.h | 12 +- src/Native/libetchash/exports.cpp | 19 +- src/Native/libetchash/internal.c | 25 +- src/Native/libetchash/internal.h | 6 +- src/Native/libfiropow/Makefile | 16 + src/Native/libfiropow/attributes.h | 33 + src/Native/libfiropow/dllmain.cpp | 19 + src/Native/libfiropow/ethash/CMakeLists.txt | 37 + .../libfiropow/ethash/bit_manipulation.h | 81 ++ src/Native/libfiropow/ethash/builtins.h | 43 ++ src/Native/libfiropow/ethash/endianness.hpp | 97 +++ .../libfiropow/ethash/ethash-internal.hpp | 68 ++ src/Native/libfiropow/ethash/ethash.cpp | 443 +++++++++++ src/Native/libfiropow/ethash/ethash.h | 138 ++++ src/Native/libfiropow/ethash/ethash.hpp | 172 +++++ src/Native/libfiropow/ethash/hash_types.h | 50 ++ src/Native/libfiropow/ethash/hash_types.hpp | 15 + src/Native/libfiropow/ethash/keccak.h | 49 ++ src/Native/libfiropow/ethash/keccak.hpp | 35 + src/Native/libfiropow/ethash/kiss99.hpp | 64 ++ src/Native/libfiropow/ethash/managed.cpp | 99 +++ src/Native/libfiropow/ethash/primes.c | 43 ++ src/Native/libfiropow/ethash/primes.h | 25 + src/Native/libfiropow/ethash/progpow.cpp | 414 ++++++++++ src/Native/libfiropow/ethash/progpow.hpp | 68 ++ src/Native/libfiropow/ethash/version.h | 18 + src/Native/libfiropow/exports.cpp | 16 + src/Native/libfiropow/keccak/CMakeLists.txt | 26 + src/Native/libfiropow/keccak/keccak.c | 123 +++ src/Native/libfiropow/keccak/keccakf1600.c | 255 +++++++ src/Native/libfiropow/keccak/keccakf800.c | 253 +++++++ src/Native/libfiropow/libfiropow.sln | 31 + src/Native/libfiropow/libfiropow.vcxproj | 206 +++++ src/Native/libfiropow/stdafx.cpp | 8 + src/Native/libfiropow/stdafx.h | 16 + src/Native/libfiropow/support/attributes.h | 33 + src/Native/libfiropow/targetver.h | 8 + src/Native/libkawpow/ethash/ethash.cpp | 705 +++++++++--------- src/Native/libkawpow/ethash/ethash.h | 181 +++-- src/Native/libkawpow/ethash/progpow.hpp | 57 +- 94 files changed, 6745 insertions(+), 1447 deletions(-) create mode 100644 examples/firo_pool.json create mode 100644 examples/ravencoin_pool.json create mode 100644 src/Miningcore.Tests/Benchmarks/Crypto/EthashBenchmarks.cs create mode 100644 src/Miningcore.Tests/Crypto/EthashTests.cs create mode 100644 src/Miningcore/Blockchain/Progpow/Custom/Firo/FiroJob.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowExtraNonceProvider.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowJob.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowPool.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowStratumMethods.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowUtils.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs create mode 100644 src/Miningcore/Blockchain/Progpow/ProgpowWorkerJob.cs delete mode 100644 src/Miningcore/Crypto/Hashing/Etchash/DagEtchash.cs delete mode 100644 src/Miningcore/Crypto/Hashing/Etchash/EtchashFull.cs create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Abstractions.cs delete mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Dag.cs create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Etchash/Cache.cs create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Etchash/EtchashLight.cs create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Ethash/Cache.cs rename src/Miningcore/Crypto/Hashing/{Ubqhash/UbqhashFull.cs => Ethash/Ethash/EthashLight.cs} (54%) create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/EthashFactory.cs create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Ubqhash/Cache.cs rename src/Miningcore/Crypto/Hashing/Ethash/{EthashFull.cs => Ubqhash/UbqhashLight.cs} (54%) create mode 100644 src/Miningcore/Crypto/Hashing/Progpow/Abstractions.cs create mode 100644 src/Miningcore/Crypto/Hashing/Progpow/Firopow/Cache.cs create mode 100644 src/Miningcore/Crypto/Hashing/Progpow/Firopow/FiropowLight.cs create mode 100644 src/Miningcore/Crypto/Hashing/Progpow/Kawpow/Cache.cs create mode 100644 src/Miningcore/Crypto/Hashing/Progpow/Kawpow/KawpowLight.cs create mode 100644 src/Miningcore/Crypto/Hashing/Progpow/ProgpowFactory.cs delete mode 100644 src/Miningcore/Crypto/Hashing/Ubqhash/DagUbqhash.cs create mode 100644 src/Miningcore/Native/FiroPow.cs create mode 100644 src/Native/libfiropow/Makefile create mode 100644 src/Native/libfiropow/attributes.h create mode 100644 src/Native/libfiropow/dllmain.cpp create mode 100644 src/Native/libfiropow/ethash/CMakeLists.txt create mode 100644 src/Native/libfiropow/ethash/bit_manipulation.h create mode 100644 src/Native/libfiropow/ethash/builtins.h create mode 100644 src/Native/libfiropow/ethash/endianness.hpp create mode 100644 src/Native/libfiropow/ethash/ethash-internal.hpp create mode 100644 src/Native/libfiropow/ethash/ethash.cpp create mode 100644 src/Native/libfiropow/ethash/ethash.h create mode 100644 src/Native/libfiropow/ethash/ethash.hpp create mode 100644 src/Native/libfiropow/ethash/hash_types.h create mode 100644 src/Native/libfiropow/ethash/hash_types.hpp create mode 100644 src/Native/libfiropow/ethash/keccak.h create mode 100644 src/Native/libfiropow/ethash/keccak.hpp create mode 100644 src/Native/libfiropow/ethash/kiss99.hpp create mode 100644 src/Native/libfiropow/ethash/managed.cpp create mode 100644 src/Native/libfiropow/ethash/primes.c create mode 100644 src/Native/libfiropow/ethash/primes.h create mode 100644 src/Native/libfiropow/ethash/progpow.cpp create mode 100644 src/Native/libfiropow/ethash/progpow.hpp create mode 100644 src/Native/libfiropow/ethash/version.h create mode 100644 src/Native/libfiropow/exports.cpp create mode 100644 src/Native/libfiropow/keccak/CMakeLists.txt create mode 100644 src/Native/libfiropow/keccak/keccak.c create mode 100644 src/Native/libfiropow/keccak/keccakf1600.c create mode 100644 src/Native/libfiropow/keccak/keccakf800.c create mode 100644 src/Native/libfiropow/libfiropow.sln create mode 100644 src/Native/libfiropow/libfiropow.vcxproj create mode 100644 src/Native/libfiropow/stdafx.cpp create mode 100644 src/Native/libfiropow/stdafx.h create mode 100644 src/Native/libfiropow/support/attributes.h create mode 100644 src/Native/libfiropow/targetver.h diff --git a/examples/callisto_pool.json b/examples/callisto_pool.json index d2d596cd1..6a927c0f1 100644 --- a/examples/callisto_pool.json +++ b/examples/callisto_pool.json @@ -99,7 +99,6 @@ } }, "chainTypeOverride": "Callisto", - "dagDir": "", "daemons": [ { "host": "127.0.0.1", diff --git a/examples/ethereum_pool.json b/examples/ethereum_pool.json index 42137b0a8..420ebc8d4 100644 --- a/examples/ethereum_pool.json +++ b/examples/ethereum_pool.json @@ -100,7 +100,6 @@ } }, "chainTypeOverride": "Ethereum", - "dagDir": "", "daemons": [ { "host": "127.0.0.1", diff --git a/examples/ethereumclassic_pool.json b/examples/ethereumclassic_pool.json index 431034714..f2f6127cc 100644 --- a/examples/ethereumclassic_pool.json +++ b/examples/ethereumclassic_pool.json @@ -99,7 +99,6 @@ } }, "chainTypeOverride": "Classic", - "dagDir": "", "daemons": [ { "host": "127.0.0.1", diff --git a/examples/firo_pool.json b/examples/firo_pool.json new file mode 100644 index 000000000..ca16ad990 --- /dev/null +++ b/examples/firo_pool.json @@ -0,0 +1,126 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "integrated", + "banOnJunkReceive": true, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": true, + "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" + }, + "pools": [{ + "id": "firo1", + "enabled": true, + "coin": "firo", + "address": "aFkp9i2yxNyRW17uX4XLDStnPoguwJ6tuL", + "GBTArgs": { + "capabilities": [ + "coinbasetxn", + "workid", + "coinbase/append" + ], + "rules": [ + "segwit" + ] + }, + "rewardRecipients": [ + { + "type": "op", + "address": "aFkp9i2yxNyRW17uX4XLDStnPoguwJ6tuL", + "percentage": 1 + } + ], + "hasBrokenSendMany": true, + "blockRefreshInterval": 0, + "jobRebroadcastTimeout": 0, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3094": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3095": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 8888, + "user": "user", + "password": "pass", + "zmqBlockNotifySocket": "tcp://127.0.0.1:8889", + "zmqBlockNotifyTopic": "rawblock" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + }, + "minersPayTxFees": true + } + }] +} diff --git a/examples/ravencoin_pool.json b/examples/ravencoin_pool.json new file mode 100644 index 000000000..2b10c1fb1 --- /dev/null +++ b/examples/ravencoin_pool.json @@ -0,0 +1,124 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "integrated", + "banOnJunkReceive": true, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": true, + "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" + }, + "pools": [{ + "id": "rvn1", + "enabled": true, + "coin": "ravencoin", + "address": "mxR4ic4Q32giqfcYqQGxDteGhzkjgA2eX6", + "GBTArgs": { + "capabilities": [ + "coinbasetxn", + "workid", + "coinbase/append" + ], + "rules": [ + "segwit" + ] + }, + "rewardRecipients": [ + { + "type": "op", + "address": "mxR4ic4Q32giqfcYqQGxDteGhzkjgA2eX6", + "percentage": 1 + } + ], + "blockRefreshInterval": 0, + "jobRebroadcastTimeout": 0, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3094": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3095": { + "listenAddress": "0.0.0.0", + "difficulty": 0.1, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 8766, + "user": "user", + "password": "pass", + "zmqBlockNotifySocket": "tcp://127.0.0.1:7772", + "zmqBlockNotifyTopic": "rawblock" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 1000, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} \ No newline at end of file diff --git a/examples/ubiq_pool.json b/examples/ubiq_pool.json index 81a001a35..9ca30f97a 100644 --- a/examples/ubiq_pool.json +++ b/examples/ubiq_pool.json @@ -99,7 +99,6 @@ } }, "chainTypeOverride": "Ubiq", - "dagDir": "", "daemons": [ { "host": "127.0.0.1", diff --git a/examples/veruscoin_pool.json b/examples/veruscoin_pool.json index 157c574c1..97c709fb4 100644 --- a/examples/veruscoin_pool.json +++ b/examples/veruscoin_pool.json @@ -53,6 +53,9 @@ "coinbasetxn", "workid", "coinbase/append" + ], + "rules": [ + "segwit" ] }, "rewardRecipients": [ @@ -106,8 +109,8 @@ "port": 7771, "user": "user", "password": "pass", - "ZmqBlockNotifySocket": "tcp://127.0.0.1:7772", - "ZmqBlockNotifyTopic": "rawblock" + "zmqBlockNotifySocket": "tcp://127.0.0.1:7772", + "zmqBlockNotifyTopic": "hashblock" } ], "paymentProcessing": { diff --git a/src/Miningcore.Tests/Benchmarks/BenchmarkRunner.cs b/src/Miningcore.Tests/Benchmarks/BenchmarkRunner.cs index cf6666f23..9dd36a0ba 100644 --- a/src/Miningcore.Tests/Benchmarks/BenchmarkRunner.cs +++ b/src/Miningcore.Tests/Benchmarks/BenchmarkRunner.cs @@ -2,6 +2,7 @@ using BenchmarkDotNet.Configs; using BenchmarkDotNet.Loggers; using BenchmarkDotNet.Running; +using Miningcore.Tests.Benchmarks.Crypto; using Miningcore.Tests.Benchmarks.Stratum; using Xunit; using Xunit.Abstractions; @@ -18,7 +19,7 @@ public Benchmarks(ITestOutputHelper output) } [Fact(Skip = "** Uncomment me to run benchmarks **")] - public void Run_Benchmarks() + public void Run_Stratum_Benchmarks() { var logger = new AccumulationLogger(); @@ -31,4 +32,19 @@ public void Run_Benchmarks() // write benchmark summary output.WriteLine(logger.GetLog()); } + + [Fact(Skip = "** Uncomment me to run benchmarks **")] + public void Run_Crypto_Benchmarks() + { + var logger = new AccumulationLogger(); + + var config = ManualConfig.Create(DefaultConfig.Instance) + .AddLogger(logger) + .WithOptions(ConfigOptions.DisableOptimizationsValidator); + + BenchmarkRunner.Run(config); + + // write benchmark summary + output.WriteLine(logger.GetLog()); + } } diff --git a/src/Miningcore.Tests/Benchmarks/Crypto/EthashBenchmarks.cs b/src/Miningcore.Tests/Benchmarks/Crypto/EthashBenchmarks.cs new file mode 100644 index 000000000..3989e0029 --- /dev/null +++ b/src/Miningcore.Tests/Benchmarks/Crypto/EthashBenchmarks.cs @@ -0,0 +1,39 @@ +using Miningcore.Extensions; +using System.Globalization; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Miningcore.Crypto.Hashing.Ethash.Ethash; +using NLog; + +namespace Miningcore.Tests.Benchmarks.Crypto; + + +[MemoryDiagnoser] +public class EthashBenchmarks : TestBase +{ + private readonly byte[] testHash = "5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0".HexToByteArray(); + private readonly ulong testNonce = ulong.Parse("50377003e5d830ca", NumberStyles.HexNumber, CultureInfo.InvariantCulture); + private const int testHeight = 60000; + + private ILogger logger; + + private readonly EthashLight ethash = new EthashLight(); + + [GlobalSetup] + public void Setup() + { + ModuleInitializer.Initialize(); + logger = new NullLogger(LogManager.LogFactory); + + ethash.Setup(3, 0); + } + + + [Benchmark] + public async Task Ethash_Compute() + { + var cache = await ethash.GetCacheAsync(logger, testHeight); + cache.Compute(logger, testHash, testNonce, out var mixDigest, out var result); + } +} + diff --git a/src/Miningcore.Tests/Crypto/EthashTests.cs b/src/Miningcore.Tests/Crypto/EthashTests.cs new file mode 100644 index 000000000..e65733076 --- /dev/null +++ b/src/Miningcore.Tests/Crypto/EthashTests.cs @@ -0,0 +1,81 @@ +using System.Globalization; +using System.Threading.Tasks; +using Miningcore.Crypto.Hashing.Ethash.Ethash; +using Miningcore.Extensions; +using NLog; +using Xunit; + +namespace Miningcore.Tests.Crypto; + + +public record TestBlock +{ + public double Difficulty { get; set; } + public byte[] Hash { get; set; } + public ulong Nonce { get; set; } + public byte[] MixDigest { get; set; } + public ulong Height { get; set; } +} + +public class EthashTests : TestBase +{ + private static readonly ILogger logger = new NullLogger(LogManager.LogFactory); + + [Fact] + public async Task Ethash_Hash() + { + var ethash = new EthashLight(); + ethash.Setup(3, 0); + + Assert.Equal("Ethash", ethash.AlgoName); + + var testBlocks = new TestBlock[] + { + new TestBlock { + Height = 22, + Hash = "372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d".HexToByteArray(), + Difficulty = 132416, + Nonce = ulong.Parse("495732e0ed7a801c", NumberStyles.HexNumber, CultureInfo.InvariantCulture), + MixDigest = "2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5".HexToByteArray(), + }, + new TestBlock { + Height = 30001, + Hash = "7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34".HexToByteArray(), + Difficulty = 1532671, + Nonce = ulong.Parse("318df1c8adef7e5e", NumberStyles.HexNumber, CultureInfo.InvariantCulture), + MixDigest = "144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84".HexToByteArray(), + }, + new TestBlock { + Height = 60000, + Hash = "5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0".HexToByteArray(), + Difficulty = 2467358, + Nonce = ulong.Parse("50377003e5d830ca", NumberStyles.HexNumber, CultureInfo.InvariantCulture), + MixDigest = "ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063".HexToByteArray(), + }, + }; + + var invalidBlock = new TestBlock + { + Height = 61439999, // 61440000 causes the c lib to crash + Hash = "foo".HexToByteArray(), + Difficulty = 0, + Nonce = ulong.Parse("cafebabec00000fe", NumberStyles.HexNumber, CultureInfo.InvariantCulture), + MixDigest = "bar".HexToByteArray(), + }; + + // test valid blocks + foreach(var testBlock in testBlocks) + { + var cache = await ethash.GetCacheAsync(logger, testBlock.Height); + var ok = cache.Compute(logger, testBlock.Hash, testBlock.Nonce, out var mixDigest, out var result); + Assert.True(ok); + Assert.Equal(testBlock.MixDigest, mixDigest); + } + + // test invalid block + var invalidCache = await ethash.GetCacheAsync(logger, invalidBlock.Height); + var invalidOk = invalidCache.Compute(logger, invalidBlock.Hash, invalidBlock.Nonce, out var invalidMixDigest, out var invalidResult); + Assert.True(invalidOk); + Assert.NotEqual(invalidBlock.MixDigest, invalidMixDigest); + } +} \ No newline at end of file diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index 3f6330ed1..6348fd620 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -8,9 +8,12 @@ using Miningcore.Blockchain.Cryptonote; using Miningcore.Blockchain.Equihash; using Miningcore.Blockchain.Ethereum; +using Miningcore.Blockchain.Progpow; using Miningcore.Configuration; using Miningcore.Crypto; using Miningcore.Crypto.Hashing.Equihash; +using Miningcore.Crypto.Hashing.Ethash; +using Miningcore.Crypto.Hashing.Progpow; using Miningcore.Messaging; using Miningcore.Mining; using Miningcore.Notifications; @@ -81,6 +84,18 @@ protected override void Load(ContainerBuilder builder) t.GetInterfaces().Any(i => i.IsAssignableFrom(typeof(IHashAlgorithm)))) .Named(t=> t.GetCustomAttributes().First().Name) .PropertiesAutowired(); + + builder.RegisterAssemblyTypes(ThisAssembly) + .Where(t => t.GetCustomAttributes().Any() && + t.GetInterfaces().Any(i => i.IsAssignableFrom(typeof(IEthashLight)))) + .Named(t => t.GetCustomAttributes().First().Name) + .PropertiesAutowired(); + + builder.RegisterAssemblyTypes(ThisAssembly) + .Where(t => t.GetCustomAttributes().Any() && + t.GetInterfaces().Any(i => i.IsAssignableFrom(typeof(IProgpowLight)))) + .Named(t => t.GetCustomAttributes().First().Name) + .PropertiesAutowired(); builder.RegisterAssemblyTypes(ThisAssembly) .Where(t => t.IsAssignableTo()) @@ -168,7 +183,6 @@ protected override void Load(ContainerBuilder builder) ////////////////////// // Ethereum - builder.RegisterType(); builder.RegisterType(); ////////////////////// @@ -179,8 +193,12 @@ protected override void Load(ContainerBuilder builder) ////////////////////// // Ergo - builder.RegisterType(); builder.RegisterType(); + + ////////////////////// + // Progpow + + builder.RegisterType(); base.Load(builder); } diff --git a/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs index 745539b22..08dbee750 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs @@ -603,38 +603,14 @@ protected virtual void SetupJobUpdates(CancellationToken ct) logger.Info(() => $"Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}"); var blockNotify = rpc.ZmqSubscribe(logger, ct, zmq) - .Where(msg => - { - bool result = false; - - try - { - var text = Encoding.UTF8.GetString(msg[0].Read()); - - result = text.StartsWith("json-minimal-chain_main:"); - } - - catch - { - } - - if(!result) - msg.Dispose(); - - return result; - }) .Select(msg => { using(msg) { - var token = GetFrameAsJToken(msg[0].Read()); - - if (token != null) - return token.Value("first_height").ToString(CultureInfo.InvariantCulture); - // 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) - return msg[0].Read().ToHexString(); + var result = msg[0].Read().ToHexString(); + return result; } }) .DistinctUntilChanged() diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs index a574e60ac..ae500d589 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJobManager.cs @@ -665,38 +665,14 @@ protected virtual void SetupJobUpdates(CancellationToken ct) logger.Info(() => $"Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}"); var blockNotify = rpc.ZmqSubscribe(logger, ct, zmq) - .Where(msg => - { - bool result = false; - - try - { - var text = Encoding.UTF8.GetString(msg[0].Read()); - - result = text.StartsWith("json-minimal-chain_main:"); - } - - catch - { - } - - if(!result) - msg.Dispose(); - - return result; - }) .Select(msg => { using(msg) { - var token = GetFrameAsJToken(msg[0].Read()); - - if (token != null) - return token.Value("first_height").ToString(CultureInfo.InvariantCulture); - // 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) - return msg[0].Read().ToHexString(); + var result = msg[0].Read().ToHexString(); + return result; } }) .DistinctUntilChanged() diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs index 9f8f993a4..335149d76 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs @@ -74,7 +74,7 @@ private EquihashJobManager createEquihashExtraNonceProvider() protected override async Task SetupJobManager(CancellationToken ct) { - manager = ctx.Resolve(new TypedParameter(typeof(IExtraNonceProvider), new EquihashExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); + manager = createEquihashExtraNonceProvider(); manager.Configure(poolConfig, clusterConfig); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs index 10a9c31dc..a6792b703 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs @@ -6,8 +6,6 @@ namespace Miningcore.Blockchain.Ethereum; public class EthereumConstants { public const ulong EpochLength = 30000; - public const ulong CacheSizeForTesting = 1024; - public const ulong DagSizeForTesting = 1024 * 32; public static BigInteger BigMaxValue = BigInteger.Pow(2, 256); public static double Pow2x32 = Math.Pow(2, 32); public static BigInteger BigPow2x32 = new(Pow2x32); diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs index a7a181e49..72564e163 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs @@ -1,8 +1,6 @@ using System.Globalization; using System.Numerics; -using Miningcore.Crypto.Hashing.Etchash; using Miningcore.Crypto.Hashing.Ethash; -using Miningcore.Crypto.Hashing.Ubqhash; using Miningcore.Extensions; using Miningcore.Stratum; using NBitcoin; @@ -12,11 +10,12 @@ namespace Miningcore.Blockchain.Ethereum; public class EthereumJob { - public EthereumJob(string id, EthereumBlockTemplate blockTemplate, ILogger logger) + public EthereumJob(string id, EthereumBlockTemplate blockTemplate, ILogger logger, IEthashLight ethash) { Id = id; BlockTemplate = blockTemplate; this.logger = logger; + this.ethash = ethash; var target = blockTemplate.Target; if(target.StartsWith("0x")) @@ -31,6 +30,7 @@ public EthereumJob(string id, EthereumBlockTemplate blockTemplate, ILogger logge public EthereumBlockTemplate BlockTemplate { get; } private readonly uint256 blockTarget; private readonly ILogger logger; + private readonly IEthashLight ethash; public record SubmitResult(Share Share, string FullNonceHex = null, string HeaderHash = null, string MixHash = null); @@ -52,155 +52,9 @@ private void RegisterNonce(StratumConnection worker, string nonce) nonces.Add(nonceLower); } } - - public async Task ProcessShareEtcHashAsync(StratumConnection worker, - string workerName, string fullNonceHex, EtchashFull etchash, 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); - - // get dag for block - var dag = await etchash.GetDagAsync(BlockTemplate.Height, logger, CancellationToken.None); - - // compute - if(!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) - throw new StratumException(StratumError.MinusOne, "bad hash"); - - // test if share meets at least workers current difficulty - 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 = mixDigest.ToHexString(true); - - share.TransactionConfirmationData = ""; - - return new SubmitResult(share, fullNonceHex, headerHash, mixHash); - } - - return new SubmitResult(share); - } public async Task ProcessShareAsync(StratumConnection worker, - string workerName, string fullNonceHex, EthashFull ethash, 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); - - // get dag for block - var dag = await ethash.GetDagAsync(BlockTemplate.Height, logger, CancellationToken.None); - - // compute - if(!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) - throw new StratumException(StratumError.MinusOne, "bad hash"); - - // test if share meets at least workers current difficulty - 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 = mixDigest.ToHexString(true); - - share.TransactionConfirmationData = ""; - - return new SubmitResult(share, fullNonceHex, headerHash, mixHash); - } - - return new SubmitResult(share); - } - - public async Task ProcessShareUbqHashAsync(StratumConnection worker, - string workerName, string fullNonceHex, UbqhashFull ubqhash, CancellationToken ct) + string workerName, string fullNonceHex, CancellationToken ct) { // dupe check lock(workerNonces) @@ -213,11 +67,11 @@ public async Task ProcessShareUbqHashAsync(StratumConnection worke if(!ulong.TryParse(fullNonceHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var fullNonce)) throw new StratumException(StratumError.MinusOne, "bad nonce " + fullNonceHex); - // get dag for block - var dag = await ubqhash.GetDagAsync(BlockTemplate.Height, logger, CancellationToken.None); + // get dag/light cache for block + var cache = await ethash.GetCacheAsync(logger, BlockTemplate.Height, ct); // compute - if(!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) + if(!cache.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) throw new StratumException(StratumError.MinusOne, "bad hash"); // test if share meets at least workers current difficulty diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index e1a82b769..031af56ac 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -8,9 +8,6 @@ using Miningcore.Blockchain.Ethereum.Configuration; using Miningcore.Blockchain.Ethereum.DaemonResponses; using Miningcore.Configuration; -using Miningcore.Crypto.Hashing.Etchash; -using Miningcore.Crypto.Hashing.Ethash; -using Miningcore.Crypto.Hashing.Ubqhash; using Miningcore.Extensions; using Miningcore.JsonRpc; using Miningcore.Messaging; @@ -47,14 +44,12 @@ public EthereumJobManager( this.clock = clock; this.extraNonceProvider = extraNonceProvider; } - + + private EthereumCoinTemplate coin; private DaemonEndpointConfig[] daemonEndpoints; private RpcClient rpc; private EthereumNetworkType networkType; private GethChainType chainType; - private EtchashFull etchash; - private EthashFull ethash; - private UbqhashFull ubqhash; private readonly IMasterClock clock; private readonly IExtraNonceProvider extraNonceProvider; private const int MaxBlockBacklog = 6; @@ -106,7 +101,7 @@ protected bool UpdateJob(EthereumBlockTemplate blockTemplate, string via = null) var jobId = NextJobId("x8"); // update template - job = new EthereumJob(jobId, blockTemplate, logger); + job = new EthereumJob(jobId, blockTemplate, logger, coin.Ethash); lock(jobLock) { @@ -339,6 +334,7 @@ public object[] GetWorkParamsForStratum(EthereumWorkerContext context) public override void Configure(PoolConfig pc, ClusterConfig cc) { extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + coin = pc.Template.As(); // extract standard daemon endpoints daemonEndpoints = pc.Daemons @@ -349,50 +345,21 @@ public override void Configure(PoolConfig pc, ClusterConfig cc) if(pc.EnableInternalStratum == true) { - var coin = pc.Template.As(); - - // ensure dag location is configured + // Automatic switch between Full DAG and Light Cache + // If dagDir provided: Full DAG + // If darDir empty: Light Cache string dagDir = null; - + if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) { dagDir = Environment.ExpandEnvironmentVariables(extraPoolConfig.DagDir); } - else - { - // Default DAG folder - switch(coin.Symbol) - { - case "ETC": - dagDir = DagEtchash.GetDefaultDagDirectory(); - break; - case "UBIQ": - dagDir = DagUbqhash.GetDefaultDagDirectory(); - break; - default: - dagDir = Dag.GetDefaultDagDirectory(); - break; - } - } - - // create it if necessary - Directory.CreateDirectory(dagDir); - - // setup ethash - switch(coin.Symbol) - { - case "ETC": - var hardForkBlock = extraPoolConfig?.ChainTypeOverride == "Classic" ? EthereumClassicConstants.HardForkBlockMainnet : EthereumClassicConstants.HardForkBlockMordor; - logger.Debug(() => $"Hard fork block on `{extraPoolConfig?.ChainTypeOverride}`: {hardForkBlock}"); - etchash = new EtchashFull(3, dagDir, hardForkBlock); - break; - case "UBIQ": - ubqhash = new UbqhashFull(3, dagDir); - break; - default: - ethash = new EthashFull(3, dagDir); - break; - } + + logger.Info(() => $"Ethasher is: {coin.Ethasher}"); + + var hardForkBlock = extraPoolConfig?.ChainTypeOverride == "Classic" ? EthereumClassicConstants.HardForkBlockMainnet : EthereumClassicConstants.HardForkBlockMordor; + // TODO: improve this + coin.Ethash.Setup(3, hardForkBlock, dagDir); } } @@ -465,87 +432,30 @@ public async Task SubmitShareV2Async(StratumConnection worker, string[] r private async Task SubmitShareAsync(StratumConnection worker, EthereumWorkerContext context, string workerName, EthereumJob job, string nonce, CancellationToken ct) { - var coin = poolConfig.Template.As(); - // validate & process - switch(coin.Symbol) + var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, workerName, nonce, ct); + + share.PoolId = poolConfig.Id; + share.NetworkDifficulty = BlockchainStats.NetworkDifficulty; + share.Source = clusterConfig.ClusterName; + share.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(share.IsBlockCandidate) { - case "ETC": - var (shareEtchash, fullNonceHexEtchash, headerHashEtchash, mixHashEtchash) = await job.ProcessShareEtcHashAsync(worker, workerName, nonce, etchash, ct); - - // enrich share with common data - shareEtchash.PoolId = poolConfig.Id; - shareEtchash.NetworkDifficulty = BlockchainStats.NetworkDifficulty; - shareEtchash.Source = clusterConfig.ClusterName; - shareEtchash.Created = clock.Now; - - // if block candidate, submit & check if accepted by network - if(shareEtchash.IsBlockCandidate) - { - logger.Info(() => $"Submitting block {shareEtchash.BlockHeight}"); - - shareEtchash.IsBlockCandidate = await SubmitBlockAsync(shareEtchash, fullNonceHexEtchash, headerHashEtchash, mixHashEtchash); - - if(shareEtchash.IsBlockCandidate) - { - logger.Info(() => $"Daemon accepted block {shareEtchash.BlockHeight} submitted by {context.Miner}"); - - OnBlockFound(); - } - } - - return shareEtchash; - case "UBIQ": - var (shareUbqhash, fullNonceHexUbqhash, headerHashUbqhash, mixHashUbqhash) = await job.ProcessShareUbqHashAsync(worker, workerName, nonce, ubqhash, ct); - - // enrich share with common data - shareUbqhash.PoolId = poolConfig.Id; - shareUbqhash.NetworkDifficulty = BlockchainStats.NetworkDifficulty; - shareUbqhash.Source = clusterConfig.ClusterName; - shareUbqhash.Created = clock.Now; - - // if block candidate, submit & check if accepted by network - if(shareUbqhash.IsBlockCandidate) - { - logger.Info(() => $"Submitting block {shareUbqhash.BlockHeight}"); - - shareUbqhash.IsBlockCandidate = await SubmitBlockAsync(shareUbqhash, fullNonceHexUbqhash, headerHashUbqhash, mixHashUbqhash); - - if(shareUbqhash.IsBlockCandidate) - { - logger.Info(() => $"Daemon accepted block {shareUbqhash.BlockHeight} submitted by {context.Miner}"); - - OnBlockFound(); - } - } - - return shareUbqhash; - default: - var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, workerName, nonce, ethash, ct); - - // enrich share with common data - share.PoolId = poolConfig.Id; - share.NetworkDifficulty = BlockchainStats.NetworkDifficulty; - 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.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, mixHash); - - if(share.IsBlockCandidate) - { - logger.Info(() => $"Daemon accepted block {share.BlockHeight} submitted by {context.Miner}"); - - OnBlockFound(); - } - } + logger.Info(() => $"Submitting block {share.BlockHeight}"); + + share.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, mixHash); + + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} submitted by {context.Miner}"); - return share; + OnBlockFound(); + } } + + return share; } public BlockchainStats BlockchainStats { get; } = new(); @@ -565,12 +475,21 @@ protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) { var response = await rpc.ExecuteAsync(logger, EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); - return response.Error == null; + if(response.Error != null) + { + logger.Error(() => $"Daemon reports: {response.Error.Message}"); + return false; + } + + return true; } protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) { var response = await rpc.ExecuteAsync(logger, EC.GetPeerCount, ct); + + if(response.Error != null) + logger.Error(() => $"Daemon reports: {response.Error.Message}"); return response.Error == null && response.Response.IntegralFromHex() > 0; } @@ -648,7 +567,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) if(poolConfig.EnableInternalStratum == true) { - // make sure we have a current DAG + // make sure we have a current DAG/light cache using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); do @@ -657,23 +576,18 @@ protected override async Task PostStartInitAsync(CancellationToken ct) if(blockTemplate != null) { - logger.Info(() => "Loading current DAG ..."); + if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) + logger.Info(() => "Loading current DAG ..."); + else + logger.Info(() => "Loading current light cache ..."); - // setup dag file - switch(coin.Symbol) - { - case "ETC": - await etchash.GetDagAsync(blockTemplate.Height, logger, ct); - break; - case "UBIQ": - await ubqhash.GetDagAsync(blockTemplate.Height, logger, ct); - break; - default: - await ethash.GetDagAsync(blockTemplate.Height, logger, ct); - break; - } + 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"); - logger.Info(() => "Loaded current DAG"); break; } diff --git a/src/Miningcore/Blockchain/Progpow/Custom/Firo/FiroJob.cs b/src/Miningcore/Blockchain/Progpow/Custom/Firo/FiroJob.cs new file mode 100644 index 000000000..49cf1babb --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/Custom/Firo/FiroJob.cs @@ -0,0 +1,205 @@ +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.Firo; + +public class FiroJob : 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.Payee)) + { + var payeeDestination = BitcoinUtils.AddressToDestination(masterNode.Payee, network); + var payeeReward = masterNode.Amount; + + tx.Outputs.Add(payeeReward, payeeDestination); + /* What is the total supply and distribution of Firo? + There will be 21.4 million Firos. Firo follows the same distribution and halving cycle as Bitcoin (every 4 years). + + A block reward of 6.25 FIRO/block is divided as follows: + + Miners (25%, 1.5625 FIRO) + Masternodes (50%, 3.125 FIRO) + Development Fund (15%, 0.9375 FIRO) + Community Fund (10%, 0.625 FIRO) + */ + //reward -= payeeReward; // FIRO 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 = "TWDxLLKsFp6qcV1LL4U2uNmW4HwMcapmMU", Amount = 93750000 }, new Founder{ Payee = "TCkC4uoErEyCB4MK3d6ouyJELoXnuyqe9L", Amount = 62500000 } }; + } + else + { + founders = new[] { new Founder{ Payee = "aLgRaYSFk6iVw2FqY1oei8Tdn2aTsGPVmP", Amount = 93750000 }, new Founder{ Payee = "aFA2TbqG9cnhhzX5Yny2pBJRK5EaEqLCH7", Amount = 62500000 } }; + } + + 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); + + /* What is the total supply and distribution of Firo? + There will be 21.4 million Firos. Firo follows the same distribution and halving cycle as Bitcoin (every 4 years). + + A block reward of 6.25 FIRO/block is divided as follows: + + Miners (25%, 1.5625 FIRO) + Masternodes (50%, 3.125 FIRO) + Development Fund (15%, 0.9375 FIRO) + Community Fund (10%, 0.625 FIRO) + */ + //reward -= payeeReward; // FIRO does not deduct payeeReward from coinbasevalue (reward) since it's the amount which goes to miners + } + } + } + + 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 new file mode 100644 index 000000000..de695d720 --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs @@ -0,0 +1,22 @@ +using System.Globalization; +using System.Numerics; + +namespace Miningcore.Blockchain.Progpow; + +public class RavencoinConstants +{ + public const int EpochLength = 7500; + public static readonly Org.BouncyCastle.Math.BigInteger Diff1B = new Org.BouncyCastle.Math.BigInteger("00ff000000000000000000000000000000000000000000000000000000", 16); + public static readonly BigInteger Diff1 = BigInteger.Parse("00ff000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); + public const int TargetPaddingLength = 32; + public const int ExtranoncePlaceHolderLength = 2; +} + +public class FiroConstants +{ + public const int EpochLength = 1300; + public static readonly Org.BouncyCastle.Math.BigInteger Diff1B = new Org.BouncyCastle.Math.BigInteger("00ffff0000000000000000000000000000000000000000000000000000", 16); + public static readonly BigInteger Diff1 = BigInteger.Parse("00ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); + public const int TargetPaddingLength = 32; + public const int ExtranoncePlaceHolderLength = 2; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowExtraNonceProvider.cs b/src/Miningcore/Blockchain/Progpow/ProgpowExtraNonceProvider.cs new file mode 100644 index 000000000..461bbd8e9 --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowExtraNonceProvider.cs @@ -0,0 +1,15 @@ +namespace Miningcore.Blockchain.Progpow; + +public class FiroExtraNonceProvider : ExtraNonceProviderBase +{ + public FiroExtraNonceProvider(string poolId, byte? clusterInstanceId) : base(poolId, FiroConstants.ExtranoncePlaceHolderLength, clusterInstanceId) + { + } +} + +public class RavencoinExtraNonceProvider : ExtraNonceProviderBase +{ + public RavencoinExtraNonceProvider(string poolId, byte? clusterInstanceId) : base(poolId, RavencoinConstants.ExtranoncePlaceHolderLength, clusterInstanceId) + { + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs b/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs new file mode 100644 index 000000000..bf37dfe8c --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs @@ -0,0 +1,297 @@ +using System.Globalization; +using System.Text; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Bitcoin.Configuration; +using Miningcore.Blockchain.Bitcoin.DaemonResponses; +using Miningcore.Configuration; +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 Contract = Miningcore.Contracts.Contract; + +namespace Miningcore.Blockchain.Progpow; + +public class ProgpowJobParams +{ + public ulong Height { get; init; } + public bool CleanJobs { get; set; } +} + +public class ProgpowJob : BitcoinJob +{ + protected IProgpowCache progpowHasher; + private new ProgpowJobParams jobParams; + + protected virtual byte[] SerializeHeader(Span coinbaseHash) + { + // build merkle-root + var merkleRoot = mt.WithFirst(coinbaseHash.ToArray()); + + // Build version + var version = BlockTemplate.Version; + +#pragma warning disable 618 + var blockHeader = new BlockHeader +#pragma warning restore 618 + { + Version = unchecked((int) version), + Bits = new Target(Encoders.Hex.DecodeData(BlockTemplate.Bits)), + HashPrevBlock = uint256.Parse(BlockTemplate.PreviousBlockhash), + HashMerkleRoot = new uint256(merkleRoot), + BlockTime = DateTimeOffset.FromUnixTimeSeconds(BlockTemplate.CurTime), + Nonce = BlockTemplate.Height + }; + + return blockHeader.ToBytes(); + } + + public virtual (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(RavencoinConstants.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); + } + + protected virtual byte[] SerializeCoinbase(string extraNonce1) + { + var extraNonce1Bytes = extraNonce1.HexToByteArray(); + + using var stream = new MemoryStream(); + { + stream.Write(coinbaseInitial); + stream.Write(extraNonce1Bytes); + stream.Write(coinbaseFinal); + + return stream.ToArray(); + } + } + + protected virtual byte[] SerializeBlock(byte[] header, byte[] coinbase, ulong nonce, byte[] mixHash) + { + var rawTransactionBuffer = BuildRawTransactionBuffer(); + var transactionCount = (uint) BlockTemplate.Transactions.Length + 1; // +1 for prepended coinbase tx + + using var stream = new MemoryStream(); + { + var bs = new BitcoinStream(stream, true); + + bs.ReadWrite(ref header); + bs.ReadWrite(ref nonce); + bs.ReadWrite(ref mixHash); + bs.ReadWriteAsVarInt(ref transactionCount); + + bs.ReadWrite(ref coinbase); + bs.ReadWrite(ref rawTransactionBuffer); + + return stream.ToArray(); + } + } + + #region API-Surface + + public virtual void Init(BlockTemplate blockTemplate, string jobId, + PoolConfig pc, BitcoinPoolConfigExtra extraPoolConfig, + ClusterConfig cc, IMasterClock clock, + IDestination poolAddressDestination, Network network, + bool isPoS, double shareMultiplier, IHashAlgorithm coinbaseHasher, + IHashAlgorithm headerHasher, IHashAlgorithm blockHasher, IProgpowCache progpowHasher) + { + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(pc); + Contract.RequiresNonNull(cc); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(poolAddressDestination); + Contract.RequiresNonNull(coinbaseHasher); + Contract.RequiresNonNull(headerHasher); + Contract.RequiresNonNull(blockHasher); + Contract.RequiresNonNull(progpowHasher); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + + this.coin = pc.Template.As(); + this.txVersion = coin.CoinbaseTxVersion; + this.network = network; + this.clock = clock; + this.poolAddressDestination = poolAddressDestination; + this.BlockTemplate = blockTemplate; + this.JobId = jobId; + + var coinbaseString = !string.IsNullOrEmpty(cc.PaymentProcessing?.CoinbaseString) ? + cc.PaymentProcessing?.CoinbaseString.Trim() : "Miningcore"; + + if(!string.IsNullOrEmpty(coinbaseString)) + this.scriptSigFinalBytes = new Script(Op.GetPushOp(Encoding.UTF8.GetBytes(coinbaseString))).ToBytes(); + + this.Difficulty = new Target(System.Numerics.BigInteger.Parse(BlockTemplate.Target, NumberStyles.HexNumber)).Difficulty; + + this.extraNoncePlaceHolderLength = RavencoinConstants.ExtranoncePlaceHolderLength; + this.shareMultiplier = shareMultiplier; + + if(coin.HasMasterNodes) + { + masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); + + if(coin.Symbol == "FIRO") + { + if(masterNodeParameters.Extra?.ContainsKey("znode") == true) + { + masterNodeParameters.Masternode = JToken.FromObject(masterNodeParameters.Extra["znode"]); + } + } + + if(!string.IsNullOrEmpty(masterNodeParameters.CoinbasePayload)) + { + txVersion = 3; + const uint txType = 5; + txVersion += txType << 16; + } + } + + if(coin.HasPayee) + payeeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); + + if (coin.HasFounderFee) + founderParameters = BlockTemplate.Extra.SafeExtensionDataAs(); + + if (coin.HasMinerFund) + minerFundParameters = BlockTemplate.Extra.SafeExtensionDataAs("coinbasetxn", "minerfund"); + + this.coinbaseHasher = coinbaseHasher; + this.headerHasher = headerHasher; + this.blockHasher = blockHasher; + this.progpowHasher = progpowHasher; + + if(!string.IsNullOrEmpty(BlockTemplate.Target)) + this.blockTargetValue = new uint256(BlockTemplate.Target); + else + { + var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); + this.blockTargetValue = tmp.ToUInt256(); + } + + BuildMerkleBranches(); + BuildCoinbase(); + + this.jobParams = new ProgpowJobParams + { + Height = BlockTemplate.Height, + CleanJobs = false + }; + } + + public new object GetJobParams(bool isNew) + { + jobParams.CleanJobs = isNew; + return jobParams; + } + + public void PrepareWorkerJob(ProgpowWorkerJob workerJob, out string headerHash) + { + workerJob.Job = this; + workerJob.Height = BlockTemplate.Height; + workerJob.Bits = BlockTemplate.Bits; + workerJob.SeedHash = progpowHasher.SeedHash.ToHexString(); + headerHash = CreateHeaderHash(workerJob); + } + + private string CreateHeaderHash(ProgpowWorkerJob workerJob) + { + var headerHasher = coin.HeaderHasherValue; + var coinbaseHasher = coin.CoinbaseHasherValue; + var extraNonce1 = workerJob.ExtraNonce1; + + var coinbase = SerializeCoinbase(extraNonce1); + Span coinbaseHash = stackalloc byte[32]; + coinbaseHasher.Digest(coinbase, coinbaseHash); + + var headerBytes = SerializeHeader(coinbaseHash); + Span headerHash = stackalloc byte[32]; + headerHasher.Digest(headerBytes, headerHash); + headerHash.Reverse(); + + return headerHash.ToHexString(); + } + + + #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 new file mode 100644 index 000000000..754380782 --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs @@ -0,0 +1,320 @@ +using Autofac; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Bitcoin.Configuration; +using Miningcore.Blockchain.Bitcoin.DaemonResponses; +using Miningcore.Blockchain.Progpow.Custom.Firo; +using Miningcore.Configuration; +using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Rpc; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using NLog; + +namespace Miningcore.Blockchain.Progpow; + +public class ProgpowJobManager : BitcoinJobManagerBase +{ + public ProgpowJobManager( + IComponentContext ctx, + IMasterClock clock, + IMessageBus messageBus, + IExtraNonceProvider extraNonceProvider) : + base(ctx, clock, messageBus, extraNonceProvider) + { + } + + private ProgpowTemplate coin; + + private async Task> GetBlockTemplateAsync(CancellationToken ct) + { + var result = await rpc.ExecuteAsync(logger, + BitcoinCommands.GetBlockTemplate, ct, extraPoolConfig?.GBTArgs ?? (object) GetBlockTemplateParams()); + + return result; + } + + private RpcResponse GetBlockTemplateFromJson(string json) + { + var result = JsonConvert.DeserializeObject(json); + + return new RpcResponse(result!.ResultAs()); + } + + private ProgpowJob CreateJob() + { + switch(coin.Symbol) + { + case "FIRO": + return new FiroJob(); + } + + return new ProgpowJob(); + } + + private double ShareMultiplier => coin.ShareMultiplier; + + + protected override void PostChainIdentifyConfigure() + { + base.PostChainIdentifyConfigure(); + + if(poolConfig.EnableInternalStratum == false || coin.HeaderHasherValue is not IHashAlgorithmInit hashInit) + return; + + if(!hashInit.DigestInit(poolConfig)) + logger.Error(() => $"{hashInit.GetType().Name} initialization failed"); + } + + protected override async Task PostStartInitAsync(CancellationToken ct) + { + 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); + + logger.Info(() => "Loaded current light cache"); + break; + } + + logger.Info(() => "Waiting for first valid block template"); + } while(await timer.WaitForNextTickAsync(ct)); + } + await base.PostStartInitAsync(ct); + } + + protected override async Task<(bool IsNew, bool Force)> UpdateJob(CancellationToken ct, bool forceUpdate, string via = null, string json = null) + { + try + { + if(forceUpdate) + lastJobRebroadcast = clock.Now; + + 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, forceUpdate); + } + + var blockTemplate = response.Response; + var job = currentJob; + + var isNew = job == null || + (blockTemplate != null && + (job.BlockTemplate?.PreviousBlockhash != blockTemplate.PreviousBlockhash || + blockTemplate.Height > job.BlockTemplate?.Height)); + + if(isNew) + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); + + if(isNew || forceUpdate) + { + job = CreateJob(); + + var blockHeight = blockTemplate?.Height ?? currentJob.BlockTemplate.Height; + + var progpowHasher = await coin.ProgpowHasher.GetCacheAsync(logger, (int) blockHeight); + + job.Init(blockTemplate, NextJobId(), + poolConfig, extraPoolConfig, clusterConfig, clock, poolAddressDestination, network, isPoS, + ShareMultiplier, coin.CoinbaseHasherValue, coin.HeaderHasherValue, coin.BlockHasherValue, progpowHasher); + + if(isNew) + { + if(via != null) + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Height}"); + + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = blockTemplate.Height; + BlockchainStats.NetworkDifficulty = job.Difficulty; + BlockchainStats.NextNetworkTarget = blockTemplate.Target; + BlockchainStats.NextNetworkBits = blockTemplate.Bits; + } + + else + { + if(via != null) + logger.Debug(() => $"Template update {blockTemplate?.Height} [{via}]"); + else + logger.Debug(() => $"Template update {blockTemplate?.Height}"); + } + + currentJob = job; + } + + return (isNew, forceUpdate); + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); + } + + return (false, forceUpdate); + } + + protected override object GetJobParamsForStratum(bool isNew) + { + var job = currentJob; + return job?.GetJobParams(isNew); + } + + #region API-Surface + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + extraPoolPaymentProcessingConfig = pc.PaymentProcessing?.Extra?.SafeExtensionDataAs(); + + if(extraPoolConfig?.MaxActiveJobs.HasValue == true) + maxActiveJobs = extraPoolConfig.MaxActiveJobs.Value; + + hasLegacyDaemon = extraPoolConfig?.HasLegacyDaemon == true; + + if(pc.EnableInternalStratum == true) + { + coin.ProgpowHasher.Setup(3); + } + + 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, + }; + + return responseData; + } + + public void PrepareWorkerJob(ProgpowWorkerJob workerJob, out string headerHash) + { + headerHash = null; + + var job = currentJob; + + if(job != null) + { + lock(job) + { + job.PrepareWorkerJob(workerJob, out headerHash); + } + } + } + + public 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 workerValue = (submitParams[0] as string)?.Trim(); + var jobId = submitParams[1] as string; + var nonce = (submitParams[2] as string)?.Substring(2); + var headerHash = (submitParams[3] as string)?.Substring(2); + var mixHash = (submitParams[4] as string)?.Substring(2); + + if(string.IsNullOrEmpty(workerValue)) + throw new StratumException(StratumError.Other, "missing or invalid workername"); + + ProgpowWorkerJob job; + + lock(context) + { + if((job = context.FindJob(jobId)) == null) + throw new StratumException(StratumError.MinusOne, "invalid jobid"); + } + + if(job == null) + throw new StratumException(StratumError.JobNotFound, "job not found"); + + + // validate & process + var (share, blockHex) = job.ProcessShare(logger, worker, nonce, headerHash, mixHash); + + // 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}]"); + + var acceptResponse = await SubmitBlockAsync(share, blockHex, ct); + + // is it still a block candidate? + share.IsBlockCandidate = acceptResponse.Accepted; + + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {context.Miner}"); + + OnBlockFound(); + + // persist the coinbase transaction-hash to allow the payment processor + // to verify later on that the pool has received the reward for the block + share.TransactionConfirmationData = acceptResponse.CoinbaseTx; + } + + else + { + // clear fields that no longer apply + share.TransactionConfirmationData = null; + } + } + + return share; + } + + #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 new file mode 100644 index 000000000..10392b257 --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs @@ -0,0 +1,422 @@ +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.Bitcoin; +using Miningcore.Configuration; +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 static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Progpow; + +[CoinFamily(CoinFamily.Progpow)] +public class ProgpowPool : PoolBase +{ + public ProgpowPool(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 ProgpowJobParams currentJobParams; + private long currentJobId; + private ProgpowJobManager manager; + private ProgpowTemplate coin; + + private string createEncodeTarget(double difficulty) + { + switch(coin.Symbol) + { + case "FIRO": + return ProgpowUtils.FiroEncodeTarget(difficulty); + + default: + return ProgpowUtils.RavencoinEncodeTarget(difficulty); + } + } + + 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(); + + var data = new object[] + { + new object[] + { + new object[] { ProgpowStratumMethods.SetDifficulty, connection.ConnectionId }, + new object[] { ProgpowStratumMethods.MiningNotify, connection.ConnectionId } + } + } + .Concat(manager.GetSubscriberData(connection)) + .ToArray(); + + await connection.RespondAsync(data, request.Id); + + // setup worker context + context.IsSubscribed = true; + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); + + // 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); + } + + var minerJobParams = CreateWorkerJob(connection, currentJobParams.CleanJobs); + // send intial update + await connection.NotifyAsync(ProgpowStratumMethods.SetDifficulty, new object[] { createEncodeTarget(context.Difficulty) }); + await connection.NotifyAsync(ProgpowStratumMethods.MiningNotify, minerJobParams); + } + + 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(); + var requestParams = request.ParamsAs(); + 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) + { + // respond + await connection.RespondAsync(context.IsAuthorized, request.Id); + + // 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}"); + + await connection.NotifyAsync(ProgpowStratumMethods.SetDifficulty, new object[] { createEncodeTarget(context.Difficulty) }); + } + } + + 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 update) + { + var context = connection.ContextAs(); + var job = new ProgpowWorkerJob(NextJobId(), context.ExtraNonce1); + + manager.PrepareWorkerJob(job, out var headerHash); + + var result = new object[] + { + job.Id, + headerHash, + job.SeedHash, + createEncodeTarget(context.Difficulty), + update, + job.Height, + job.Bits + }; + + // update context + lock(context) + { + context.AddJob(job); + } + + return result; + } + + private string NextJobId() + { + return Interlocked.Increment(ref currentJobId).ToString(CultureInfo.InvariantCulture); + } + + 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); + await connection.RespondAsync(true, request.Id); + + // 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 job) + { + logger.Info(() => $"Broadcasting jobs"); + + currentJobParams = job as ProgpowJobParams; + + await Guard(() => ForEachMinerAsync(async (connection, _) => + { + var context = connection.ContextAs(); + + var minerJobParams = CreateWorkerJob(connection, currentJobParams.CleanJobs); + + if(context.ApplyPendingDifficulty()) + await connection.NotifyAsync(ProgpowStratumMethods.SetDifficulty, new object[] { createEncodeTarget(context.Difficulty) }); + + // send job + await connection.NotifyAsync(ProgpowStratumMethods.MiningNotify, minerJobParams); + })); + } + + public override double HashrateFromShares(double shares, double interval) + { + var multiplier = BitcoinConstants.Pow2x32; + var result = shares * multiplier / interval; + + if(coin.HashrateMultiplier.HasValue) + result *= coin.HashrateMultiplier.Value; + + return result; + } + + public override double ShareMultiplier => coin.ShareMultiplier; + + private ProgpowJobManager createProgpowExtraNonceProvider() + { + switch(coin.Symbol) + { + case "FIRO": + return ctx.Resolve(new TypedParameter(typeof(IExtraNonceProvider), new FiroExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); + + default: + return ctx.Resolve(new TypedParameter(typeof(IExtraNonceProvider), new RavencoinExtraNonceProvider(poolConfig.Id, clusterConfig.InstanceId))); + } + } + + #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 = createProgpowExtraNonceProvider(); + + 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 ProgpowWorkerContext(); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + try + { + switch(request.Method) + { + case ProgpowStratumMethods.Subscribe: + await OnSubscribeAsync(connection, tsRequest); + break; + + case ProgpowStratumMethods.Authorize: + await OnAuthorizeAsync(connection, tsRequest, ct); + break; + + case ProgpowStratumMethods.SubmitShare: + await OnSubmitAsync(connection, tsRequest, ct); + break; + + case BitcoinStratumMethods.MiningMultiVersion: + // ignored + break; + + case BitcoinStratumMethods.ExtraNonceSubscribe: + case BitcoinStratumMethods.GetTransactions: + case ProgpowStratumMethods.SubmitHashrate: + logger.Debug(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); + break; + + default: + logger.Debug(() => $"[{connection.ConnectionId}] Unknown RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.NotifyAsync(ProgpowStratumMethods.UnknownMethod, request); + 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, currentJobParams.CleanJobs); + await connection.NotifyAsync(ProgpowStratumMethods.SetDifficulty, new object[] { createEncodeTarget(connection.Context.Difficulty) }); + await connection.NotifyAsync(ProgpowStratumMethods.MiningNotify, minerJobParams); + } + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowStratumMethods.cs b/src/Miningcore/Blockchain/Progpow/ProgpowStratumMethods.cs new file mode 100644 index 000000000..3fcc0a173 --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowStratumMethods.cs @@ -0,0 +1,39 @@ +namespace Miningcore.Blockchain.Progpow; + +public class ProgpowStratumMethods +{ + /// + /// 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. 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 submit hashrate + /// + public const string SubmitHashrate = "eth_submitHashrate"; + + /// + /// Used to signal the miner to stop submitting shares under the new difficulty. + /// + public const string SetDifficulty = "mining.set_target"; + + /// + /// Used to notify unknown RPC methods + /// + public const string UnknownMethod = "client.mining.unknown"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowUtils.cs b/src/Miningcore/Blockchain/Progpow/ProgpowUtils.cs new file mode 100644 index 000000000..ea878a1b9 --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowUtils.cs @@ -0,0 +1,51 @@ +using Miningcore.Extensions; +using Org.BouncyCastle.Math; + +namespace Miningcore.Blockchain.Progpow; + +public static class ProgpowUtils +{ + public static string FiroEncodeTarget(double difficulty) + { + string result; + var diff = BigInteger.ValueOf((long) (difficulty * 255d)); + var quotient = FiroConstants.Diff1B.Divide(diff).Multiply(BigInteger.ValueOf(255)); + var bytes = quotient.ToByteArray().AsSpan(); + Span padded = stackalloc byte[FiroConstants.TargetPaddingLength]; + + var padLength = FiroConstants.TargetPaddingLength - bytes.Length; + + if(padLength > 0) + { + bytes.CopyTo(padded.Slice(padLength, bytes.Length)); + result = padded.ToHexString(0, FiroConstants.TargetPaddingLength); + } + + else + result = bytes.ToHexString(0, FiroConstants.TargetPaddingLength); + + return result; + } + + public static string RavencoinEncodeTarget(double difficulty) + { + string result; + var diff = BigInteger.ValueOf((long) (difficulty * 255d)); + var quotient = RavencoinConstants.Diff1B.Divide(diff).Multiply(BigInteger.ValueOf(255)); + var bytes = quotient.ToByteArray().AsSpan(); + Span padded = stackalloc byte[RavencoinConstants.TargetPaddingLength]; + + var padLength = RavencoinConstants.TargetPaddingLength - bytes.Length; + + if(padLength > 0) + { + bytes.CopyTo(padded.Slice(padLength, bytes.Length)); + result = padded.ToHexString(0, RavencoinConstants.TargetPaddingLength); + } + + else + result = bytes.ToHexString(0, RavencoinConstants.TargetPaddingLength); + + return result; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs b/src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs new file mode 100644 index 000000000..fbf439aee --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowWorkerContext.cs @@ -0,0 +1,36 @@ +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Progpow; + +public class ProgpowWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } + + private List ValidJobs { get; } = new(); + + public void AddJob(ProgpowWorkerJob job) + { + ValidJobs.Insert(0, job); + + while(ValidJobs.Count > 4) + ValidJobs.RemoveAt(ValidJobs.Count - 1); + } + + public ProgpowWorkerJob FindJob(string jobId) + { + return ValidJobs.FirstOrDefault(x => x.Id == jobId); + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowWorkerJob.cs b/src/Miningcore/Blockchain/Progpow/ProgpowWorkerJob.cs new file mode 100644 index 000000000..e796b1e03 --- /dev/null +++ b/src/Miningcore/Blockchain/Progpow/ProgpowWorkerJob.cs @@ -0,0 +1,65 @@ +using System.Collections.Concurrent; +using System.Globalization; +using System.Text; +using Miningcore.Stratum; +using NLog; +using Contract = Miningcore.Contracts.Contract; + +namespace Miningcore.Blockchain.Progpow; + +public class ProgpowWorkerJob +{ + public ProgpowWorkerJob(string jobId, string extraNonce1) + { + Id = jobId; + ExtraNonce1 = extraNonce1; + } + + public string Id { get; } + public ProgpowJob Job { get; set; } + public uint Height { get; set; } + public string ExtraNonce1 { get; set; } + public string Bits { get; set; } + public string SeedHash { get; set; } + + private readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); + + private bool RegisterSubmit(string nonce, string headerHash, string mixHash) + { + var key = new StringBuilder() + .Append(nonce) // lowercase as we don't want to accept case-sensitive values as valid. + .Append(headerHash) + .Append(mixHash) + .ToString(); + + return submissions.TryAdd(key, true); + } + + public (Share Share, string BlockHex) ProcessShare(ILogger logger, StratumConnection worker, string nonce, string headerHash, string mixHash) + { + Contract.RequiresNonNull(worker); + Contract.Requires(!string.IsNullOrEmpty(nonce)); + + var context = worker.ContextAs(); + + // mixHash + if(mixHash.Length != 64) + throw new StratumException(StratumError.Other, $"incorrect size of mixHash: {mixHash}"); + + // validate nonce + if(nonce.Length != 16) + throw new StratumException(StratumError.Other, $"incorrect size of nonce: {nonce}"); + + // check if nonce is within range + if(nonce.IndexOf(context.ExtraNonce1[0..4], StringComparison.OrdinalIgnoreCase) != 0) + throw new StratumException(StratumError.Other, $"nonce out of range: {nonce}"); + + // dupe check + if(!RegisterSubmit(nonce, headerHash, mixHash)) + throw new StratumException(StratumError.DuplicateShare, "duplicate share"); + + var nonceLong = ulong.Parse(nonce, NumberStyles.HexNumber); + + return Job.ProcessShareInternal(logger, worker, nonceLong, headerHash, mixHash); + } +} \ No newline at end of file diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index c851dfe6c..5d3ea3702 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -36,6 +36,9 @@ public enum CoinFamily [EnumMember(Value = "ergo")] Ergo, + + [EnumMember(Value = "progpow")] + Progpow, } public abstract partial class CoinTemplate @@ -140,6 +143,7 @@ public abstract partial class CoinTemplate {CoinFamily.Cryptonote, typeof(CryptonoteCoinTemplate)}, {CoinFamily.Ethereum, typeof(EthereumCoinTemplate)}, {CoinFamily.Ergo, typeof(ErgoCoinTemplate)}, + {CoinFamily.Progpow, typeof(ProgpowTemplate)}, }; } @@ -586,12 +590,25 @@ public partial class EthereumCoinTemplate : CoinTemplate [DefaultValue(EthereumSubfamily.None)] [JsonConverter(typeof(StringEnumConverter), true)] public EthereumSubfamily Subfamily { get; set; } + + /// + /// Which hashing algorithm to use. (ethash, etchash or ubqhash) + /// + public string Ethasher { get; set; } = "ethash"; } public partial class ErgoCoinTemplate : CoinTemplate { } +public partial class ProgpowTemplate : BitcoinTemplate +{ + /// + /// Which hashing algorithm to use. (kawpow or firopow) + /// + public string Progpower { get; set; } = "kawpow"; +} + #endregion // Coin Definitions public enum PayoutScheme diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index 3bfb710f4..d88b26378 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -4,6 +4,8 @@ using JetBrains.Annotations; using Miningcore.Crypto; using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Crypto.Hashing.Ethash; +using Miningcore.Crypto.Hashing.Progpow; using NBitcoin; using Newtonsoft.Json; @@ -197,10 +199,22 @@ public override string GetAlgorithmName() public partial class EthereumCoinTemplate { #region Overrides of CoinTemplate + + public EthereumCoinTemplate() + { + ethashLightValue = new Lazy(() => + EthashFactory.GetEthash(ComponentContext, Ethasher)); + } + + private readonly Lazy ethashLightValue; + + public IComponentContext ComponentContext { get; [UsedImplicitly] init; } + + public IEthashLight Ethash => ethashLightValue.Value; public override string GetAlgorithmName() { - return "Ethhash"; + return Ethash.AlgoName; } #endregion @@ -218,6 +232,28 @@ public override string GetAlgorithmName() #endregion } +public partial class ProgpowTemplate +{ + #region Overrides of CoinTemplate + + public ProgpowTemplate() : base() + { + progpowLightValue = new Lazy(() => + ProgpowFactory.GetProgpow(ComponentContext, Progpower)); + } + + private readonly Lazy progpowLightValue; + + public IProgpowLight ProgpowHasher => progpowLightValue.Value; + + public override string GetAlgorithmName() + { + return ProgpowHasher.AlgoName; + } + + #endregion +} + public partial class PoolConfig { /// diff --git a/src/Miningcore/Crypto/Hashing/Etchash/DagEtchash.cs b/src/Miningcore/Crypto/Hashing/Etchash/DagEtchash.cs deleted file mode 100644 index 447c372ce..000000000 --- a/src/Miningcore/Crypto/Hashing/Etchash/DagEtchash.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System.Diagnostics; -using System.Text; -using Miningcore.Blockchain.Ethereum; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Native; -using Miningcore.Notifications.Messages; -using NLog; - -namespace Miningcore.Crypto.Hashing.Etchash; - -public class DagEtchash : IDisposable -{ - public DagEtchash(ulong epoch) - { - Epoch = epoch; - } - - public ulong Epoch { get; set; } - - private IntPtr handle = IntPtr.Zero; - private static readonly Semaphore sem = new(1, 1); - - internal static IMessageBus messageBus; - - public DateTime LastUsed { get; set; } - - public static unsafe string GetDefaultDagDirectory() - { - var chars = new byte[512]; - - fixed (byte* data = chars) - { - if(EtcHash.ethash_get_default_dirname(data, chars.Length)) - { - int length; - for(length = 0; length < chars.Length; length++) - { - if(data[length] == 0) - break; - } - - return Encoding.UTF8.GetString(data, length); - } - } - - return null; - } - - public void Dispose() - { - if(handle != IntPtr.Zero) - { - EtcHash.ethash_full_delete(handle); - handle = IntPtr.Zero; - } - } - - public async Task GenerateAsync(string dagDir, ulong dagEpochLength, ILogger logger, CancellationToken ct) - { - Contract.Requires(!string.IsNullOrEmpty(dagDir)); - - if(handle == IntPtr.Zero) - { - await Task.Run(() => - { - try - { - sem.WaitOne(); - - // re-check after obtaining lock - if(handle != IntPtr.Zero) - return; - - logger.Info(() => $"Generating DAG for epoch {Epoch}"); - - var started = DateTime.Now; - var block = Epoch * dagEpochLength; - - logger.Debug(() => $"Epoch length used: {dagEpochLength}"); - - // Generate a temporary cache - var light = EtcHash.ethash_light_new(block); - - try - { - // Generate the actual DAG - handle = EtcHash.ethash_full_new(dagDir, light, progress => - { - logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); - - return !ct.IsCancellationRequested ? 0 : 1; - }); - - if(handle == IntPtr.Zero) - throw new OutOfMemoryException("ethash_full_new IO or memory error"); - - logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); - } - - finally - { - if(light != IntPtr.Zero) - EtcHash.ethash_light_delete(light); - } - } - - finally - { - sem.Release(); - } - }, ct); - } - } - - public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) - { - Contract.RequiresNonNull(hash); - - var sw = Stopwatch.StartNew(); - - mixDigest = null; - result = null; - - var value = new EtcHash.ethash_return_value(); - - fixed (byte* input = hash) - { - EtcHash.ethash_full_compute(handle, input, nonce, ref value); - } - - if(value.success) - { - mixDigest = value.mix_hash.value; - result = value.result.value; - } - - messageBus?.SendTelemetry("Etchash", TelemetryCategory.Hash, sw.Elapsed, value.success); - - return value.success; - } -} diff --git a/src/Miningcore/Crypto/Hashing/Etchash/EtchashFull.cs b/src/Miningcore/Crypto/Hashing/Etchash/EtchashFull.cs deleted file mode 100644 index a5edd7aa0..000000000 --- a/src/Miningcore/Crypto/Hashing/Etchash/EtchashFull.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Miningcore.Blockchain.Ethereum; -using Miningcore.Contracts; -using NLog; - -namespace Miningcore.Crypto.Hashing.Etchash; - -public class EtchashFull : IDisposable -{ - public EtchashFull(int numCaches, string dagDir, ulong hardForkBlock) - { - Contract.Requires(!string.IsNullOrEmpty(dagDir)); - - this.numCaches = numCaches; - this.dagDir = dagDir; - this.hardForkBlock = hardForkBlock; - } - - 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 DagEtchash future; - private readonly string dagDir; - private readonly ulong hardForkBlock; - - public void Dispose() - { - foreach(var value in caches.Values) - value.Dispose(); - } - - public async Task GetDagAsync(ulong block, ILogger logger, CancellationToken ct) - { - var dagEpochLength = block >= hardForkBlock ? EthereumClassicConstants.EpochLength : EthereumConstants.EpochLength; - logger.Debug(() => $"Epoch length used: {dagEpochLength}"); - var epoch = block / dagEpochLength; - DagEtchash result; - - lock(cacheLock) - { - if(numCaches == 0) - numCaches = 3; - - if(!caches.TryGetValue(epoch, out result)) - { - // No cached DAG, 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 DAG for epoch {epochToEvict} in favour of epoch {epoch}"); - toEvict.Dispose(); - caches.Remove(key); - } - - // If we have the new DAG pre-generated, use that, otherwise create a new one - if(future != null && future.Epoch == epoch) - { - logger.Debug(() => $"Using pre-generated DAG for epoch {epoch}"); - - result = future; - future = null; - } - - else - { - logger.Info(() => $"No pre-generated DAG available, creating new for epoch {epoch}"); - result = new DagEtchash(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 DAG for epoch {epoch + 1}"); - future = new DagEtchash(epoch + 1); - -#pragma warning disable 4014 - future.GenerateAsync(dagDir, dagEpochLength, logger, ct); -#pragma warning restore 4014 - } - - result.LastUsed = DateTime.Now; - } - - // get/generate current one - await result.GenerateAsync(dagDir, dagEpochLength, logger, ct); - - return result; - } -} diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Abstractions.cs b/src/Miningcore/Crypto/Hashing/Ethash/Abstractions.cs new file mode 100644 index 000000000..e8a9643ec --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/Abstractions.cs @@ -0,0 +1,15 @@ +using NLog; + +namespace Miningcore.Crypto.Hashing.Ethash; + +public interface IEthashLight : IDisposable +{ + void Setup(int totalCache, ulong hardForkBlock, string dagDir = null); + Task GetCacheAsync(ILogger logger, ulong block, CancellationToken ct); + string AlgoName { get; } +} + +public interface IEthashCache : IDisposable +{ + bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result); +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Dag.cs b/src/Miningcore/Crypto/Hashing/Ethash/Dag.cs deleted file mode 100644 index 5bb3936d2..000000000 --- a/src/Miningcore/Crypto/Hashing/Ethash/Dag.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Diagnostics; -using System.Text; -using Miningcore.Blockchain.Ethereum; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Native; -using Miningcore.Notifications.Messages; -using NLog; - -namespace Miningcore.Crypto.Hashing.Ethash; - -public class Dag : IDisposable -{ - public Dag(ulong epoch) - { - Epoch = epoch; - } - - public ulong Epoch { get; set; } - - private IntPtr handle = IntPtr.Zero; - private static readonly Semaphore sem = new(1, 1); - - internal static IMessageBus messageBus; - - public DateTime LastUsed { get; set; } - - public static unsafe string GetDefaultDagDirectory() - { - var chars = new byte[512]; - - fixed (byte* data = chars) - { - if(EthHash.ethash_get_default_dirname(data, chars.Length)) - { - int length; - for(length = 0; length < chars.Length; length++) - { - if(data[length] == 0) - break; - } - - return Encoding.UTF8.GetString(data, length); - } - } - - return null; - } - - public void Dispose() - { - if(handle != IntPtr.Zero) - { - EthHash.ethash_full_delete(handle); - handle = IntPtr.Zero; - } - } - - public async Task GenerateAsync(string dagDir, ILogger logger, CancellationToken ct) - { - Contract.Requires(!string.IsNullOrEmpty(dagDir)); - - if(handle == IntPtr.Zero) - { - await Task.Run(() => - { - try - { - sem.WaitOne(); - - // re-check after obtaining lock - if(handle != IntPtr.Zero) - return; - - logger.Info(() => $"Generating DAG for epoch {Epoch}"); - - var started = DateTime.Now; - var block = Epoch * EthereumConstants.EpochLength; - - // Generate a temporary cache - var light = EthHash.ethash_light_new(block); - - try - { - // Generate the actual DAG - handle = EthHash.ethash_full_new(dagDir, light, progress => - { - logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); - - return !ct.IsCancellationRequested ? 0 : 1; - }); - - if(handle == IntPtr.Zero) - throw new OutOfMemoryException("ethash_full_new IO or memory error"); - - logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); - } - - finally - { - if(light != IntPtr.Zero) - EthHash.ethash_light_delete(light); - } - } - - finally - { - sem.Release(); - } - }, ct); - } - } - - public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) - { - Contract.RequiresNonNull(hash); - - var sw = Stopwatch.StartNew(); - - mixDigest = null; - result = null; - - var value = new EthHash.ethash_return_value(); - - fixed (byte* input = hash) - { - EthHash.ethash_full_compute(handle, input, nonce, ref value); - } - - if(value.success) - { - mixDigest = value.mix_hash.value; - result = value.result.value; - } - - messageBus?.SendTelemetry("Ethash", TelemetryCategory.Hash, sw.Elapsed, value.success); - - return value.success; - } -} diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Etchash/Cache.cs b/src/Miningcore/Crypto/Hashing/Ethash/Etchash/Cache.cs new file mode 100644 index 000000000..e64e92eea --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/Etchash/Cache.cs @@ -0,0 +1,170 @@ +using System.Diagnostics; +using System.Text; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ethash.Etchash; + +[Identifier("etchash")] +public class Cache : IEthashCache +{ + public Cache(ulong epoch, string dagDir = null) + { + Epoch = epoch; + this.dagDir = dagDir; + LastUsed = DateTime.Now; + } + + private IntPtr handle = IntPtr.Zero; + private bool isGenerated = false; + private readonly object genLock = new(); + internal static IMessageBus messageBus; + private ulong hardForkBlock; + public ulong Epoch { get; } + private string dagDir; + public DateTime LastUsed { get; set; } + + public static unsafe string GetDefaultdagDirectory() + { + var chars = new byte[512]; + + fixed (byte* data = chars) + { + if(EtcHash.ethash_get_default_dirname(data, chars.Length)) + { + int length; + for(length = 0; length < chars.Length; length++) + { + if(data[length] == 0) + break; + } + + return Encoding.UTF8.GetString(data, length); + } + } + + return null; + } + + public void Dispose() + { + if(handle != IntPtr.Zero) + { + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + EtcHash.ethash_full_delete(handle); + } + // Light Cache + else + { + EtcHash.ethash_light_delete(handle); + } + + handle = IntPtr.Zero; + } + } + + public async Task GenerateAsync(ILogger logger, ulong epochLength, ulong hardForkBlock, CancellationToken ct) + { + if(handle == IntPtr.Zero) + { + await Task.Run(() => + { + lock(genLock) + { + if(!isGenerated) + { + // re-check after obtaining lock + if(handle != IntPtr.Zero) + return; + + this.hardForkBlock = hardForkBlock; + var started = DateTime.Now; + var block = Epoch * epochLength; + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + logger.Debug(() => $"Generating DAG for epoch {Epoch}"); + logger.Debug(() => $"Epoch length used: {epochLength}"); + + // Generate a temporary cache + var light = EtcHash.ethash_light_new(block, hardForkBlock); + + // Generate the actual DAG + handle = EtcHash.ethash_full_new(dagDir, light, hardForkBlock, progress => + { + logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); + + return !ct.IsCancellationRequested ? 0 : 1; + }); + + if(handle == IntPtr.Zero) + throw new OutOfMemoryException("ethash_full_new IO or memory error"); + + if(light != IntPtr.Zero) + EthHash.ethash_light_delete(light); + + logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); + } + // Light Cache + else + { + logger.Debug(() => $"Generating cache for epoch {Epoch}"); + + handle = EtcHash.ethash_light_new(block, hardForkBlock); + + logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); + } + + isGenerated = true; + } + } + }, ct); + } + } + + public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) + { + Contract.RequiresNonNull(hash); + + var sw = Stopwatch.StartNew(); + + mixDigest = null; + result = null; + + var value = new EtcHash.ethash_return_value(); + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + fixed (byte* input = hash) + { + EtcHash.ethash_full_compute(handle, input, nonce, ref value); + } + } + // Light Cache + else + { + fixed(byte* input = hash) + { + EtcHash.ethash_light_compute(handle, input, nonce, this.hardForkBlock, ref value); + } + } + + if(value.success) + { + mixDigest = value.mix_hash.value; + result = value.result.value; + } + + messageBus?.SendTelemetry("Etchash", TelemetryCategory.Hash, sw.Elapsed, value.success); + + return value.success; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Etchash/EtchashLight.cs b/src/Miningcore/Crypto/Hashing/Ethash/Etchash/EtchashLight.cs new file mode 100644 index 000000000..8f86dbbfd --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/Etchash/EtchashLight.cs @@ -0,0 +1,96 @@ +using System.Text; +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using Miningcore.Native; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ethash.Etchash; + +[Identifier("etchash")] +public class EtchashLight : IEthashLight +{ + public void Setup(int totalCache, ulong hardForkBlock, string dagDir = null) + { + this.numCaches = totalCache; + this.hardForkBlock = hardForkBlock; + this.dagDir = dagDir; + } + + 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; + private string dagDir; + private ulong hardForkBlock; + public string AlgoName { get; } = "Etchash"; + + public void Dispose() + { + foreach(var value in caches.Values) + value.Dispose(); + } + + public async Task GetCacheAsync(ILogger logger, ulong block, CancellationToken ct) + { + var epochLength = block >= this.hardForkBlock ? EthereumClassicConstants.EpochLength : EthereumConstants.EpochLength; + logger.Debug(() => $"Epoch length used: {epochLength}"); + var epoch = block / 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, dagDir); + } + + 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, dagDir); + +#pragma warning disable 4014 + future.GenerateAsync(logger, epochLength, this.hardForkBlock, ct); +#pragma warning restore 4014 + } + + result.LastUsed = DateTime.Now; + } + + // get/generate current one + await result.GenerateAsync(logger, epochLength, this.hardForkBlock, ct); + + return result; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Ethash/Cache.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ethash/Cache.cs new file mode 100644 index 000000000..8351f264b --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ethash/Cache.cs @@ -0,0 +1,169 @@ +using System.Diagnostics; +using System.Text; +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ethash.Ethash; + +[Identifier("ethash")] +public class Cache : IEthashCache +{ + public Cache(ulong epoch, string dagDir = null) + { + Epoch = epoch; + this.dagDir = dagDir; + LastUsed = DateTime.Now; + } + + private IntPtr handle = IntPtr.Zero; + private bool isGenerated = false; + private readonly object genLock = new(); + internal static IMessageBus messageBus; + public ulong Epoch { get; } + private string dagDir; + public DateTime LastUsed { get; set; } + + public static unsafe string GetDefaultdagDirectory() + { + var chars = new byte[512]; + + fixed (byte* data = chars) + { + if(EthHash.ethash_get_default_dirname(data, chars.Length)) + { + int length; + for(length = 0; length < chars.Length; length++) + { + if(data[length] == 0) + break; + } + + return Encoding.UTF8.GetString(data, length); + } + } + + return null; + } + + public void Dispose() + { + if(handle != IntPtr.Zero) + { + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + EthHash.ethash_full_delete(handle); + } + // Light Cache + else + { + EthHash.ethash_light_delete(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; + var block = Epoch * EthereumConstants.EpochLength; + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + logger.Debug(() => $"Generating DAG for epoch {Epoch}"); + logger.Debug(() => $"Epoch length used: {EthereumConstants.EpochLength}"); + + // Generate a temporary cache + var light = EthHash.ethash_light_new(block); + + // Generate the actual DAG + handle = EthHash.ethash_full_new(dagDir, light, progress => + { + logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); + + return !ct.IsCancellationRequested ? 0 : 1; + }); + + if(handle == IntPtr.Zero) + throw new OutOfMemoryException("ethash_full_new IO or memory error"); + + if(light != IntPtr.Zero) + EthHash.ethash_light_delete(light); + + logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); + } + // Light Cache + else + { + logger.Debug(() => $"Generating cache for epoch {Epoch}"); + + handle = EthHash.ethash_light_new(block); + + logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); + } + + isGenerated = true; + } + } + }, ct); + } + } + + public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) + { + Contract.RequiresNonNull(hash); + + var sw = Stopwatch.StartNew(); + + mixDigest = null; + result = null; + + var value = new EthHash.ethash_return_value(); + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + fixed (byte* input = hash) + { + EthHash.ethash_full_compute(handle, input, nonce, ref value); + } + } + // Light Cache + else + { + fixed(byte* input = hash) + { + EthHash.ethash_light_compute(handle, input, nonce, ref value); + } + } + + if(value.success) + { + mixDigest = value.mix_hash.value; + result = value.result.value; + } + + messageBus?.SendTelemetry("Ethash", TelemetryCategory.Hash, sw.Elapsed, value.success); + + return value.success; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ubqhash/UbqhashFull.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ethash/EthashLight.cs similarity index 54% rename from src/Miningcore/Crypto/Hashing/Ubqhash/UbqhashFull.cs rename to src/Miningcore/Crypto/Hashing/Ethash/Ethash/EthashLight.cs index dbbb62bc3..cdad772b4 100644 --- a/src/Miningcore/Crypto/Hashing/Ubqhash/UbqhashFull.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ethash/EthashLight.cs @@ -1,24 +1,26 @@ +using System.Text; using Miningcore.Blockchain.Ethereum; using Miningcore.Contracts; +using Miningcore.Native; using NLog; -namespace Miningcore.Crypto.Hashing.Ubqhash; +namespace Miningcore.Crypto.Hashing.Ethash.Ethash; -public class UbqhashFull : IDisposable +[Identifier("ethash")] +public class EthashLight : IEthashLight { - public UbqhashFull(int numCaches, string dagDir) + public void Setup(int totalCache, ulong hardForkBlock, string dagDir = null) { - Contract.Requires(!string.IsNullOrEmpty(dagDir)); - - this.numCaches = numCaches; + this.numCaches = totalCache; this.dagDir = dagDir; } 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 DagUbqhash future; - private readonly string dagDir; + private readonly Dictionary caches = new(); + private Cache future; + private string dagDir; + public string AlgoName { get; } = "Ethash"; public void Dispose() { @@ -26,10 +28,10 @@ public void Dispose() value.Dispose(); } - public async Task GetDagAsync(ulong block, ILogger logger, CancellationToken ct) + public async Task GetCacheAsync(ILogger logger, ulong block, CancellationToken ct) { var epoch = block / EthereumConstants.EpochLength; - DagUbqhash result; + Cache result; lock(cacheLock) { @@ -38,22 +40,22 @@ public async Task GetDagAsync(ulong block, ILogger logger, Cancellat if(!caches.TryGetValue(epoch, out result)) { - // No cached DAG, evict the oldest if the cache limit was reached + // 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 DAG for epoch {epochToEvict} in favour of epoch {epoch}"); + logger.Info(() => $"Evicting cache for epoch {epochToEvict} in favour of epoch {epoch}"); toEvict.Dispose(); caches.Remove(key); } - // If we have the new DAG pre-generated, use that, otherwise create a new one + // 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 DAG for epoch {epoch}"); + logger.Debug(() => $"Using pre-generated cache for epoch {epoch}"); result = future; future = null; @@ -61,8 +63,8 @@ public async Task GetDagAsync(ulong block, ILogger logger, Cancellat else { - logger.Info(() => $"No pre-generated DAG available, creating new for epoch {epoch}"); - result = new DagUbqhash(epoch); + logger.Info(() => $"No pre-generated cache available, creating new for epoch {epoch}"); + result = new Cache(epoch, dagDir); } caches[epoch] = result; @@ -71,11 +73,11 @@ public async Task GetDagAsync(ulong block, ILogger logger, Cancellat // If we used up the future cache, or need a refresh, regenerate else if(future == null || future.Epoch <= epoch) { - logger.Info(() => $"Pre-generating DAG for epoch {epoch + 1}"); - future = new DagUbqhash(epoch + 1); + logger.Info(() => $"Pre-generating cache for epoch {epoch + 1}"); + future = new Cache(epoch + 1, dagDir); #pragma warning disable 4014 - future.GenerateAsync(dagDir, logger, ct); + future.GenerateAsync(logger, ct); #pragma warning restore 4014 } @@ -83,8 +85,8 @@ public async Task GetDagAsync(ulong block, ILogger logger, Cancellat } // get/generate current one - await result.GenerateAsync(dagDir, logger, ct); + await result.GenerateAsync(logger, ct); return result; } -} +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ethash/EthashFactory.cs b/src/Miningcore/Crypto/Hashing/Ethash/EthashFactory.cs new file mode 100644 index 000000000..4d833075a --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/EthashFactory.cs @@ -0,0 +1,25 @@ +using System.Collections.Concurrent; +using Autofac; + +namespace Miningcore.Crypto.Hashing.Ethash; + +public static class EthashFactory +{ + private static readonly ConcurrentDictionary cacheFull = new(); + + public static IEthashLight GetEthash(IComponentContext ctx, string name) + { + if(name == "") + return null; + + // check cache + if(cacheFull.TryGetValue(name, out var result)) + return result; + + result = ctx.ResolveNamed(name); + + cacheFull.TryAdd(name, result); + + return result; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Ubqhash/Cache.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ubqhash/Cache.cs new file mode 100644 index 000000000..94b5d3037 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ubqhash/Cache.cs @@ -0,0 +1,166 @@ +using System.Diagnostics; +using System.Text; +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ethash.Ubqhash; + +[Identifier("ubqhash")] +public class Cache : IEthashCache +{ + public Cache(ulong epoch, string dagDir = null) + { + Epoch = epoch; + this.dagDir = dagDir; + LastUsed = DateTime.Now; + } + + private IntPtr handle = IntPtr.Zero; + private bool isGenerated = false; + private readonly object genLock = new(); + internal static IMessageBus messageBus; + public ulong Epoch { get; } + private string dagDir; + public DateTime LastUsed { get; set; } + + public static unsafe string GetDefaultdagDirectory() + { + var chars = new byte[512]; + + fixed (byte* data = chars) + { + if(UbqHash.ethash_get_default_dirname(data, chars.Length)) + { + int length; + for(length = 0; length < chars.Length; length++) + { + if(data[length] == 0) + break; + } + + return Encoding.UTF8.GetString(data, length); + } + } + + return null; + } + + public void Dispose() + { + if(handle != IntPtr.Zero) + { + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + UbqHash.ethash_full_delete(handle); + } + // Light Cache + else + { + UbqHash.ethash_light_delete(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; + var block = Epoch * EthereumConstants.EpochLength; + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + logger.Debug(() => $"Generating DAG for epoch {Epoch}"); + logger.Debug(() => $"Epoch length used: {EthereumConstants.EpochLength}"); + + // Generate a temporary cache + var light = UbqHash.ethash_light_new(block); + + // Generate the actual DAG + handle = UbqHash.ethash_full_new(dagDir, light, progress => + { + logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); + + return !ct.IsCancellationRequested ? 0 : 1; + }); + + if(handle == IntPtr.Zero) + throw new OutOfMemoryException("ethash_full_new IO or memory error"); + + logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); + } + // Light Cache + else + { + logger.Debug(() => $"Generating cache for epoch {Epoch}"); + + handle = UbqHash.ethash_light_new(block); + + logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); + } + + isGenerated = true; + } + } + }, ct); + } + } + + public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) + { + Contract.RequiresNonNull(hash); + + var sw = Stopwatch.StartNew(); + + mixDigest = null; + result = null; + + var value = new UbqHash.ethash_return_value(); + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + fixed (byte* input = hash) + { + UbqHash.ethash_full_compute(handle, input, nonce, ref value); + } + } + // Light Cache + else + { + fixed(byte* input = hash) + { + UbqHash.ethash_light_compute(handle, input, nonce, ref value); + } + } + + if(value.success) + { + mixDigest = value.mix_hash.value; + result = value.result.value; + } + + messageBus?.SendTelemetry("Ubqhash", TelemetryCategory.Hash, sw.Elapsed, value.success); + + return value.success; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ubqhash/UbqhashLight.cs similarity index 54% rename from src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs rename to src/Miningcore/Crypto/Hashing/Ethash/Ubqhash/UbqhashLight.cs index a625010a5..1eaa4dfb6 100644 --- a/src/Miningcore/Crypto/Hashing/Ethash/EthashFull.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ubqhash/UbqhashLight.cs @@ -1,24 +1,26 @@ +using System.Text; using Miningcore.Blockchain.Ethereum; using Miningcore.Contracts; +using Miningcore.Native; using NLog; -namespace Miningcore.Crypto.Hashing.Ethash; +namespace Miningcore.Crypto.Hashing.Ethash.Ubqhash; -public class EthashFull : IDisposable +[Identifier("ubqhash")] +public class UbqhashLight : IEthashLight { - public EthashFull(int numCaches, string dagDir) + public void Setup(int totalCache, ulong hardForkBlock, string dagDir = null) { - Contract.Requires(!string.IsNullOrEmpty(dagDir)); - - this.numCaches = numCaches; + this.numCaches = totalCache; this.dagDir = dagDir; } 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 Dag future; - private readonly string dagDir; + private readonly Dictionary caches = new(); + private Cache future; + private string dagDir; + public string AlgoName { get; } = "Ubqhash"; public void Dispose() { @@ -26,10 +28,10 @@ public void Dispose() value.Dispose(); } - public async Task GetDagAsync(ulong block, ILogger logger, CancellationToken ct) + public async Task GetCacheAsync(ILogger logger, ulong block, CancellationToken ct) { var epoch = block / EthereumConstants.EpochLength; - Dag result; + Cache result; lock(cacheLock) { @@ -38,22 +40,22 @@ public async Task GetDagAsync(ulong block, ILogger logger, CancellationToke if(!caches.TryGetValue(epoch, out result)) { - // No cached DAG, evict the oldest if the cache limit was reached + // 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 DAG for epoch {epochToEvict} in favour of epoch {epoch}"); + logger.Info(() => $"Evicting cache for epoch {epochToEvict} in favour of epoch {epoch}"); toEvict.Dispose(); caches.Remove(key); } - // If we have the new DAG pre-generated, use that, otherwise create a new one + // 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 DAG for epoch {epoch}"); + logger.Debug(() => $"Using pre-generated cache for epoch {epoch}"); result = future; future = null; @@ -61,8 +63,8 @@ public async Task GetDagAsync(ulong block, ILogger logger, CancellationToke else { - logger.Info(() => $"No pre-generated DAG available, creating new for epoch {epoch}"); - result = new Dag(epoch); + logger.Info(() => $"No pre-generated cache available, creating new for epoch {epoch}"); + result = new Cache(epoch, dagDir); } caches[epoch] = result; @@ -71,11 +73,11 @@ public async Task GetDagAsync(ulong block, ILogger logger, CancellationToke // If we used up the future cache, or need a refresh, regenerate else if(future == null || future.Epoch <= epoch) { - logger.Info(() => $"Pre-generating DAG for epoch {epoch + 1}"); - future = new Dag(epoch + 1); + logger.Info(() => $"Pre-generating cache for epoch {epoch + 1}"); + future = new Cache(epoch + 1, dagDir); #pragma warning disable 4014 - future.GenerateAsync(dagDir, logger, ct); + future.GenerateAsync(logger, ct); #pragma warning restore 4014 } @@ -83,8 +85,8 @@ public async Task GetDagAsync(ulong block, ILogger logger, CancellationToke } // get/generate current one - await result.GenerateAsync(dagDir, logger, ct); + await result.GenerateAsync(logger, ct); return result; } -} +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Abstractions.cs b/src/Miningcore/Crypto/Hashing/Progpow/Abstractions.cs new file mode 100644 index 000000000..756cfc858 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Progpow/Abstractions.cs @@ -0,0 +1,16 @@ +using NLog; + +namespace Miningcore.Crypto.Hashing.Progpow; + +public interface IProgpowLight : IDisposable +{ + void Setup(int totalCache, ulong hardForkBlock = 0); + Task GetCacheAsync(ILogger logger, int block); + string AlgoName { get; } +} + +public interface IProgpowCache : IDisposable +{ + public byte[] SeedHash { get; set; } + bool Compute(ILogger logger, int blockNumber, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result); +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Firopow/Cache.cs b/src/Miningcore/Crypto/Hashing/Progpow/Firopow/Cache.cs new file mode 100644 index 000000000..a90ad833a --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Progpow/Firopow/Cache.cs @@ -0,0 +1,96 @@ +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.Firopow; + +[Identifier("firopow")] +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) + { + FiroPow.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 = FiroPow.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 = FiroPow.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 FiroPow.Ethash_result(); + + var inputHash = new FiroPow.Ethash_hash256(); + inputHash.bytes = hash; + + fixed(byte* input = hash) + { + value = FiroPow.hash(handle, blockNumber, ref inputHash, nonce); + } + + if(value.final_hash.bytes == null) + { + logger.Error(() => $"FiroPow.hash returned null"); + return false; + } + + mixDigest = value.mix_hash.bytes; + result = value.final_hash.bytes; + + messageBus?.SendTelemetry("Firopow", TelemetryCategory.Hash, sw.Elapsed, true); + + return true; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Firopow/FiropowLight.cs b/src/Miningcore/Crypto/Hashing/Progpow/Firopow/FiropowLight.cs new file mode 100644 index 000000000..c52aadce6 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Progpow/Firopow/FiropowLight.cs @@ -0,0 +1,87 @@ +using Miningcore.Blockchain.Progpow; +using NLog; + +namespace Miningcore.Crypto.Hashing.Progpow.Firopow; + +[Identifier("firopow")] +public class FiropowLight : 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; } = "FiroPow"; + + public void Dispose() + { + foreach(var value in caches.Values) + value.Dispose(); + } + + public async Task GetCacheAsync(ILogger logger, int block) + { + var epoch = block / FiroConstants.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/Kawpow/Cache.cs b/src/Miningcore/Crypto/Hashing/Progpow/Kawpow/Cache.cs new file mode 100644 index 000000000..0803911be --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Progpow/Kawpow/Cache.cs @@ -0,0 +1,96 @@ +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.Kawpow; + +[Identifier("kawpow")] +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) + { + KawPow.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 = KawPow.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 = KawPow.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 KawPow.Ethash_result(); + + var inputHash = new KawPow.Ethash_hash256(); + inputHash.bytes = hash; + + fixed(byte* input = hash) + { + value = KawPow.hash(handle, blockNumber, ref inputHash, nonce); + } + + if(value.final_hash.bytes == null) + { + logger.Error(() => $"KawPow.hash returned null"); + return false; + } + + mixDigest = value.mix_hash.bytes; + result = value.final_hash.bytes; + + messageBus?.SendTelemetry("Kawpow", TelemetryCategory.Hash, sw.Elapsed, true); + + return true; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Progpow/Kawpow/KawpowLight.cs b/src/Miningcore/Crypto/Hashing/Progpow/Kawpow/KawpowLight.cs new file mode 100644 index 000000000..7d28df56d --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Progpow/Kawpow/KawpowLight.cs @@ -0,0 +1,87 @@ +using Miningcore.Blockchain.Progpow; +using NLog; + +namespace Miningcore.Crypto.Hashing.Progpow.Kawpow; + +[Identifier("kawpow")] +public class KawpowLight : 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; } = "KawPow"; + + public void Dispose() + { + foreach(var value in caches.Values) + value.Dispose(); + } + + public async Task GetCacheAsync(ILogger logger, int block) + { + var epoch = block / RavencoinConstants.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/ProgpowFactory.cs b/src/Miningcore/Crypto/Hashing/Progpow/ProgpowFactory.cs new file mode 100644 index 000000000..517570882 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Progpow/ProgpowFactory.cs @@ -0,0 +1,25 @@ +using System.Collections.Concurrent; +using Autofac; + +namespace Miningcore.Crypto.Hashing.Progpow; + +public static class ProgpowFactory +{ + private static readonly ConcurrentDictionary cacheFull = new(); + + public static IProgpowLight GetProgpow(IComponentContext ctx, string name) + { + if(name == "") + return null; + + // check cache + if(cacheFull.TryGetValue(name, out var result)) + return result; + + result = ctx.ResolveNamed(name); + + cacheFull.TryAdd(name, result); + + return result; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ubqhash/DagUbqhash.cs b/src/Miningcore/Crypto/Hashing/Ubqhash/DagUbqhash.cs deleted file mode 100644 index 9902f7cab..000000000 --- a/src/Miningcore/Crypto/Hashing/Ubqhash/DagUbqhash.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Diagnostics; -using System.Text; -using Miningcore.Blockchain.Ethereum; -using Miningcore.Contracts; -using Miningcore.Extensions; -using Miningcore.Messaging; -using Miningcore.Native; -using Miningcore.Notifications.Messages; -using NLog; - -namespace Miningcore.Crypto.Hashing.Ubqhash; - -public class DagUbqhash : IDisposable -{ - public DagUbqhash(ulong epoch) - { - Epoch = epoch; - } - - public ulong Epoch { get; set; } - - private IntPtr handle = IntPtr.Zero; - private static readonly Semaphore sem = new(1, 1); - - internal static IMessageBus messageBus; - - public DateTime LastUsed { get; set; } - - public static unsafe string GetDefaultDagDirectory() - { - var chars = new byte[512]; - - fixed (byte* data = chars) - { - if(UbqHash.ethash_get_default_dirname(data, chars.Length)) - { - int length; - for(length = 0; length < chars.Length; length++) - { - if(data[length] == 0) - break; - } - - return Encoding.UTF8.GetString(data, length); - } - } - - return null; - } - - public void Dispose() - { - if(handle != IntPtr.Zero) - { - UbqHash.ethash_full_delete(handle); - handle = IntPtr.Zero; - } - } - - public async Task GenerateAsync(string dagDir, ILogger logger, CancellationToken ct) - { - Contract.Requires(!string.IsNullOrEmpty(dagDir)); - - if(handle == IntPtr.Zero) - { - await Task.Run(() => - { - try - { - sem.WaitOne(); - - // re-check after obtaining lock - if(handle != IntPtr.Zero) - return; - - logger.Info(() => $"Generating DAG for epoch {Epoch}"); - - var started = DateTime.Now; - var block = Epoch * EthereumConstants.EpochLength; - - // Generate a temporary cache - var light = UbqHash.ethash_light_new(block); - - try - { - // Generate the actual DAG - handle = UbqHash.ethash_full_new(dagDir, light, progress => - { - logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); - - return !ct.IsCancellationRequested ? 0 : 1; - }); - - if(handle == IntPtr.Zero) - throw new OutOfMemoryException("ethash_full_new IO or memory error"); - - logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); - } - - finally - { - if(light != IntPtr.Zero) - UbqHash.ethash_light_delete(light); - } - } - - finally - { - sem.Release(); - } - }, ct); - } - } - - public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) - { - Contract.RequiresNonNull(hash); - - var sw = Stopwatch.StartNew(); - - mixDigest = null; - result = null; - - var value = new UbqHash.ethash_return_value(); - - fixed (byte* input = hash) - { - UbqHash.ethash_full_compute(handle, input, nonce, ref value); - } - - if(value.success) - { - mixDigest = value.mix_hash.value; - result = value.result.value; - } - - messageBus?.SendTelemetry("Ubqhash", TelemetryCategory.Hash, sw.Elapsed, value.success); - - return value.success; - } -} diff --git a/src/Miningcore/Native/EtcHash.cs b/src/Miningcore/Native/EtcHash.cs index 3dd80fd5f..209e55eb6 100644 --- a/src/Miningcore/Native/EtcHash.cs +++ b/src/Miningcore/Native/EtcHash.cs @@ -29,7 +29,7 @@ public struct ethash_return_value /// The block number for which to create the handler /// Newly allocated ethash_light handler or NULL [DllImport("libetchash", EntryPoint = "ethash_light_new_export", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr ethash_light_new(ulong block_number); + public static extern IntPtr ethash_light_new(ulong block_number, ulong fork_block); /// /// Frees a previously allocated ethash_light handler @@ -46,7 +46,7 @@ public struct ethash_return_value /// The nonce to pack into the mix /// an object of ethash_return_value_t holding the return values [DllImport("libetchash", EntryPoint = "ethash_light_compute_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void ethash_light_compute(IntPtr handle, byte* header_hash, ulong nonce, ref ethash_return_value result); + public static extern void ethash_light_compute(IntPtr handle, byte* header_hash, ulong nonce, ulong fork_block, ref ethash_return_value result); /// /// Allocate and initialize a new ethash_full handler @@ -64,7 +64,7 @@ public struct ethash_return_value /// /// [DllImport("libetchash", EntryPoint = "ethash_full_new_export", CallingConvention = CallingConvention.Cdecl)] - public static extern IntPtr ethash_full_new(string dagDir, IntPtr light, ethash_callback_t callback); + public static extern IntPtr ethash_full_new(string dagDir, IntPtr light, ulong fork_block, ethash_callback_t callback); /// /// Frees a previously allocated ethash_full handler diff --git a/src/Miningcore/Native/FiroPow.cs b/src/Miningcore/Native/FiroPow.cs new file mode 100644 index 000000000..cbf2a51cc --- /dev/null +++ b/src/Miningcore/Native/FiroPow.cs @@ -0,0 +1,37 @@ +using System.Runtime.InteropServices; + +// ReSharper disable FieldCanBeMadeReadOnly.Local +// ReSharper disable MemberCanBePrivate.Local +// ReSharper disable InconsistentNaming + +namespace Miningcore.Native; + +public static unsafe class FiroPow +{ + [DllImport("libfiropow", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr CreateContext(int epoch_number); + + [DllImport("libfiropow", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] + public static extern void DestroyContext(IntPtr context); + + [DllImport("libfiropow", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)] + public static extern Ethash_result hash(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce); + + [DllImport("libfiropow", 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/KawPow.cs b/src/Miningcore/Native/KawPow.cs index c80643952..42d797f3b 100644 --- a/src/Miningcore/Native/KawPow.cs +++ b/src/Miningcore/Native/KawPow.cs @@ -8,17 +8,20 @@ namespace Miningcore.Native; public static unsafe class KawPow { - [DllImport("libethash", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr CreateContext(int epoch_number); + [DllImport("libkawpow", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr CreateContext(int epoch_number); - [DllImport("libethash", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] - private static extern void DestroyContext(IntPtr context); + [DllImport("libkawpow", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)] + public static extern void DestroyContext(IntPtr context); - [DllImport("libethash", EntryPoint = "hashext", CallingConvention = CallingConvention.Cdecl)] - private static extern Ethash_result hashext(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce, ref Ethash_hash256 mix_hash, ref Ethash_hash256 boundary1, ref Ethash_hash256 boundary2, out int retcode); + [DllImport("libkawpow", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)] + public static extern Ethash_result hash(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce); + + [DllImport("libkawpow", EntryPoint = "ethash_calculate_epoch_seed", CallingConvention = CallingConvention.Cdecl)] + public static extern Ethash_hash256 calculate_epoch_seed(int epoch_number); [StructLayout(LayoutKind.Explicit)] - private struct Ethash_hash256 + public struct Ethash_hash256 { [FieldOffset(0)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] @@ -26,9 +29,9 @@ private struct Ethash_hash256 } [StructLayout(LayoutKind.Sequential)] - private struct Ethash_result + 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/Payments/PayoutManager.cs b/src/Miningcore/Payments/PayoutManager.cs index 95288c7c9..69fcee656 100644 --- a/src/Miningcore/Payments/PayoutManager.cs +++ b/src/Miningcore/Payments/PayoutManager.cs @@ -142,6 +142,9 @@ private static CoinFamily HandleFamilyOverride(CoinFamily family, PoolConfig poo return CoinFamily.Bitcoin; break; + + case CoinFamily.Progpow: + return CoinFamily.Bitcoin; } return family; diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index 42bc7761d..e13011bc7 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -27,7 +27,9 @@ using Miningcore.Configuration; using Miningcore.Crypto.Hashing.Algorithms; using Miningcore.Crypto.Hashing.Equihash; -using Miningcore.Crypto.Hashing.Ethash; +using Miningcore.Crypto.Hashing.Ethash.Etchash; +using Miningcore.Crypto.Hashing.Ethash.Ethash; +using Miningcore.Crypto.Hashing.Ethash.Ubqhash; using Miningcore.Extensions; using Miningcore.Messaging; using Miningcore.Mining; @@ -782,7 +784,13 @@ private static async Task PreFlightChecks(IServiceProvider services) EquihashSolver.MaxThreads = clusterConfig.EquihashMaxThreads ?? 1; // Configure Ethhash - Dag.messageBus = messageBus; + Miningcore.Crypto.Hashing.Ethash.Ethash.Cache.messageBus = messageBus; + + // Configure Etchash + Miningcore.Crypto.Hashing.Ethash.Etchash.Cache.messageBus = messageBus; + + // Configure Ubqhash + Miningcore.Crypto.Hashing.Ethash.Ubqhash.Cache.messageBus = messageBus; // Configure Verthash Verthash.messageBus = messageBus; diff --git a/src/Miningcore/build-libs-linux.sh b/src/Miningcore/build-libs-linux.sh index fbf0f9d27..97f4569ba 100755 --- a/src/Miningcore/build-libs-linux.sh +++ b/src/Miningcore/build-libs-linux.sh @@ -30,6 +30,8 @@ export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_AVX $HAVE (cd ../Native/libcryptonote && make clean && make) && mv ../Native/libcryptonote/libcryptonote.so "$OutDir" (cd ../Native/libcryptonight && make clean && make) && mv ../Native/libcryptonight/libcryptonight.so "$OutDir" (cd ../Native/libverushash && make clean && make) && mv ../Native/libverushash/libverushash.so "$OutDir" +(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 /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") diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 5b7e682fb..3cac0efca 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -2228,6 +2228,66 @@ "explorerTxLink": "https://explorer.radiantblockchain.org/tx/{0}", "explorerAccountLink": "https://explorer.radiantblockchain.org/address/{0}" }, + "ravencoin": { + "name": "Ravencoin", + "symbol": "RVN", + "family": "progpow", + "website": "https://ravencoin.org/", + "market": "https://coinmarketcap.com/currencies/ravencoin/", + "twitter": "https://twitter.com/Ravencoin", + "telegram": "https://t.me/RavencoinDev", + "discord": "https://discordapp.com/invite/jn6uhur", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "sha256d" + } + ] + }, + "shareMultiplier": 1, + "progpower": "kawpow", + "explorerBlockLink": "https://ravencoin.network/rvn/block/$hash$", + "explorerTxLink": "https://ravencoin.network/rvn/transaction/{0}", + "explorerAccountLink": "https://ravencoin.network/rvn/address/{0}" + }, + "firo": { + "name": "Firo", + "symbol": "FIRO", + "family": "progpow", + "website": "https://firo.org/", + "market": "https://coinmarketcap.com/currencies/firo/", + "twitter": "https://twitter.com/firoorg", + "telegram": "https://t.me/firoorg", + "discord": "https://discord.gg/TGZPRbRT3Y", + "coinbaseHasher": { + "hash": "sha256d" + }, + "headerHasher": { + "hash": "sha256d" + }, + "blockHasher": { + "hash": "reverse", + "args": [ + { + "hash": "sha256d" + } + ] + }, + "hasFounderFee": true, + "hasMasterNodes": true, + "shareMultiplier": 1, + "progpower": "firopow", + "explorerBlockLink": "https://explorer.firo.org/block/$hash$", + "explorerTxLink": "https://explorer.firo.org/tx/{0}", + "explorerAccountLink": "https://explorer.firo.org/address/{0}" + }, "novo": { "name": "Novo", "symbol": "NOVO", @@ -4317,7 +4377,8 @@ "uncle": "https://explorer.callisto.network/blocks/$height$" }, "explorerTxLink": "https://explorer.callisto.network/tx/{0}", - "explorerAccountLink": "https://explorer.callisto.network/address/{0}" + "explorerAccountLink": "https://explorer.callisto.network/address/{0}", + "ethasher": "ethash" }, "ethereum": { "name": "Ethereum", @@ -4334,7 +4395,8 @@ "uncle": "https://etherscan.io/uncle/$height$" }, "explorerTxLink": "https://etherscan.io/tx/{0}", - "explorerAccountLink": "https://etherscan.io/address/{0}" + "explorerAccountLink": "https://etherscan.io/address/{0}", + "ethasher": "ethash" }, "ethereumclassic": { "name": "Ethereum Classic", @@ -4351,7 +4413,8 @@ "uncle": "https://blockscout.com/etc/mainnet/block/$height$" }, "explorerTxLink": "https://blockscout.com/etc/mainnet/tx/{0}", - "explorerAccountLink": "https://blockscout.com/etc/mainnet/address/{0}" + "explorerAccountLink": "https://blockscout.com/etc/mainnet/address/{0}", + "ethasher": "etchash" }, "ethereum-pow": { "name": "EthereumPoW", @@ -4368,7 +4431,8 @@ "uncle": "https://www.oklink.com/en/ethw/uncle/$height$" }, "explorerTxLink": "https://www.oklink.com/en/ethw/tx/{0}", - "explorerAccountLink": "https://www.oklink.com/en/ethw/address/{0}" + "explorerAccountLink": "https://www.oklink.com/en/ethw/address/{0}", + "ethasher": "ethash" }, "etherone": { "name": "EtherOne", @@ -4385,7 +4449,8 @@ "uncle": "https://blockscout.etherone.one/uncles/$height$" }, "explorerTxLink": "https://blockscout.etherone.one/tx/{0}", - "explorerAccountLink": "https://blockscout.etherone.one/address/{0}" + "explorerAccountLink": "https://blockscout.etherone.one/address/{0}", + "ethasher": "ethash" }, "pinkchain": { "name": "PinkChain", @@ -4402,7 +4467,8 @@ "uncle": "https://pinkscan.org/uncle/$height$" }, "explorerTxLink": "https://pinkscan.org/tx/{0}", - "explorerAccountLink": "https://pinkscan.org/address/{0}" + "explorerAccountLink": "https://pinkscan.org/address/{0}", + "ethasher": "ethash" }, "ubiq": { "name": "Ubiq", @@ -4419,7 +4485,8 @@ "uncle": "https://ubiqscan.io/uncle/$height$" }, "explorerTxLink": "https://ubiqscan.io/tx/{0}", - "explorerAccountLink": "https://ubiqscan.io/address/{0}" + "explorerAccountLink": "https://ubiqscan.io/address/{0}", + "ethasher": "ubqhash" }, "ergo": { "name": "Ergo", diff --git a/src/Native/libetchash/ethash.h b/src/Native/libetchash/ethash.h index 875f5e891..ae8c7cbf5 100644 --- a/src/Native/libetchash/ethash.h +++ b/src/Native/libetchash/ethash.h @@ -33,7 +33,7 @@ #define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17 #define ETHASH_EPOCH_LENGTH 30000U #define ETHASH_EPOCH_LENGTH_NEW 60000U -#define ETCHASH_FORK_BLOCK 11700000 // classic mainnet +//#define ETCHASH_FORK_BLOCK 11700000 // classic mainnet //#define ETCHASH_FORK_BLOCK 2520000 // mordor #define ETHASH_MIX_BYTES 128 #define ETHASH_HASH_BYTES 64 @@ -76,10 +76,11 @@ typedef struct ethash_return_value { * Allocate and initialize a new ethash_light handler * * @param block_number The block number for which to create the handler + * @param fork_block The block number when ETH forked ETC (Useful for mordor) * @return Newly allocated ethash_light handler or NULL in case of * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() */ -ethash_light_t ethash_light_new(uint64_t block_number); +ethash_light_t ethash_light_new(uint64_t block_number, uint64_t const fork_block); /** * Frees a previously allocated ethash_light handler * @param light The light handler to free @@ -91,18 +92,21 @@ void ethash_light_delete(ethash_light_t light); * @param light The light client handler * @param header_hash The header hash to pack into the mix * @param nonce The nonce to pack into the mix + * @param fork_block The block number when ETH forked ETC (Useful for mordor) * @return an object of ethash_return_value_t holding the return values */ ethash_return_value_t ethash_light_compute( ethash_light_t light, ethash_h256_t const header_hash, - uint64_t nonce + uint64_t nonce, + uint64_t const fork_block ); /** * Allocate and initialize a new ethash_full handler * * @param light The light handler containing the cache. + * @param fork_block The block number when ETH forked ETC (Useful for mordor) * @param callback A callback function with signature of @ref ethash_callback_t * It accepts an unsigned with which a progress of DAG calculation * can be displayed. If all goes well the callback should return 0. @@ -113,7 +117,7 @@ ethash_return_value_t ethash_light_compute( * @return Newly allocated ethash_full handler or NULL in case of * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() */ -ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback); +ethash_full_t ethash_full_new(ethash_light_t light, uint64_t const fork_block, ethash_callback_t callback); /** * Frees a previously allocated ethash_full handler diff --git a/src/Native/libetchash/exports.cpp b/src/Native/libetchash/exports.cpp index 506cb149c..cfe217fa8 100644 --- a/src/Native/libetchash/exports.cpp +++ b/src/Native/libetchash/exports.cpp @@ -27,19 +27,19 @@ extern "C" bool ethash_get_default_dirname(char* strbuf, size_t buffsize); #define MODULE_API #endif -extern "C" MODULE_API uint64_t ethash_get_datasize_export(uint64_t const block_number) +extern "C" MODULE_API uint64_t ethash_get_datasize_export(uint64_t const block_number, uint64_t const fork_block) { - return ethash_get_datasize(block_number); + return ethash_get_datasize(block_number, fork_block); } -extern "C" MODULE_API uint64_t ethash_get_cachesize_export(uint64_t const block_number) +extern "C" MODULE_API uint64_t ethash_get_cachesize_export(uint64_t const block_number, uint64_t const fork_block) { - return ethash_get_cachesize(block_number); + return ethash_get_cachesize(block_number, fork_block); } -extern "C" MODULE_API ethash_light_t ethash_light_new_export(uint64_t block_number) +extern "C" MODULE_API ethash_light_t ethash_light_new_export(uint64_t block_number, uint64_t const fork_block) { - return ethash_light_new(block_number); + return ethash_light_new(block_number, fork_block); } extern "C" MODULE_API void ethash_light_delete_export(ethash_light_t light) @@ -51,14 +51,15 @@ extern "C" MODULE_API void ethash_light_compute_export( ethash_light_t light, ethash_h256_t const *header_hash, uint64_t nonce, + uint64_t const fork_block, ethash_return_value_t *result) { - *result = ethash_light_compute(light, *header_hash, nonce); + *result = ethash_light_compute(light, *header_hash, nonce, fork_block); } -extern "C" MODULE_API ethash_full_t ethash_full_new_export(const char *dirname, ethash_light_t light, ethash_callback_t callback) +extern "C" MODULE_API ethash_full_t ethash_full_new_export(const char *dirname, ethash_light_t light, uint64_t const fork_block, ethash_callback_t callback) { - uint64_t full_size = ethash_get_datasize(light->block_number); + uint64_t full_size = ethash_get_datasize(light->block_number, fork_block); ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); return ethash_full_new_internal(dirname, seedhash, full_size, light, callback); } diff --git a/src/Native/libetchash/internal.c b/src/Native/libetchash/internal.c index 3ab113d47..c2ee634a3 100644 --- a/src/Native/libetchash/internal.c +++ b/src/Native/libetchash/internal.c @@ -45,14 +45,14 @@ #include #endif -uint64_t ethash_get_datasize(uint64_t const block_number) +uint64_t ethash_get_datasize(uint64_t const block_number, uint64_t const fork_block) { - return dag_sizes[etchash_calc_epoch(block_number)]; + return dag_sizes[etchash_calc_epoch(block_number, fork_block)]; } -uint64_t ethash_get_cachesize(uint64_t const block_number) +uint64_t ethash_get_cachesize(uint64_t const block_number, uint64_t const fork_block) { - return cache_sizes[etchash_calc_epoch(block_number)]; + return cache_sizes[etchash_calc_epoch(block_number, fork_block)]; } // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) @@ -320,11 +320,11 @@ ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t cons return NULL; } -ethash_light_t ethash_light_new(uint64_t block_number) +ethash_light_t ethash_light_new(uint64_t block_number, uint64_t const fork_block) { ethash_h256_t seedhash = ethash_get_seedhash(block_number); ethash_light_t ret; - ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash); + ret = ethash_light_new_internal(ethash_get_cachesize(block_number, fork_block), &seedhash); ret->block_number = block_number; return ret; } @@ -337,9 +337,9 @@ void ethash_light_delete(ethash_light_t light) free(light); } -uint64_t static etchash_calc_epoch(uint64_t const block_number) +uint64_t static etchash_calc_epoch(uint64_t const block_number, uint64_t const fork_block) { - uint64_t epochLen = block_number >= ETCHASH_FORK_BLOCK ? ETHASH_EPOCH_LENGTH_NEW : ETHASH_EPOCH_LENGTH; + uint64_t epochLen = block_number >= fork_block ? ETHASH_EPOCH_LENGTH_NEW : ETHASH_EPOCH_LENGTH; return block_number / epochLen; } @@ -361,10 +361,11 @@ ethash_return_value_t ethash_light_compute_internal( ethash_return_value_t ethash_light_compute( ethash_light_t light, ethash_h256_t const header_hash, - uint64_t nonce + uint64_t nonce, + uint64_t const fork_block ) { - uint64_t full_size = ethash_get_datasize(light->block_number); + uint64_t full_size = ethash_get_datasize(light->block_number, fork_block); return ethash_light_compute_internal(light, full_size, header_hash, nonce); } @@ -463,13 +464,13 @@ ethash_full_t ethash_full_new_internal( return NULL; } -ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback) +ethash_full_t ethash_full_new(ethash_light_t light, uint64_t const fork_block, ethash_callback_t callback) { char strbuf[256]; if (!ethash_get_default_dirname(strbuf, 256)) { return NULL; } - uint64_t full_size = ethash_get_datasize(light->block_number); + uint64_t full_size = ethash_get_datasize(light->block_number, fork_block); ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback); } diff --git a/src/Native/libetchash/internal.h b/src/Native/libetchash/internal.h index 7d630d272..087c2f7f7 100644 --- a/src/Native/libetchash/internal.h +++ b/src/Native/libetchash/internal.h @@ -153,9 +153,9 @@ void ethash_quick_hash( ethash_h256_t const* mix_hash ); -uint64_t ethash_get_datasize(uint64_t const block_number); -uint64_t ethash_get_cachesize(uint64_t const block_number); -static uint64_t etchash_calc_epoch(uint64_t const block_number); +uint64_t ethash_get_datasize(uint64_t const block_number, uint64_t const fork_block); +uint64_t ethash_get_cachesize(uint64_t const block_number, uint64_t const fork_block); +static uint64_t etchash_calc_epoch(uint64_t const block_number, uint64_t const fork_block); /** * Compute the memory data for a full node's memory diff --git a/src/Native/libfiropow/Makefile b/src/Native/libfiropow/Makefile new file mode 100644 index 000000000..c5da90fd4 --- /dev/null +++ b/src/Native/libfiropow/Makefile @@ -0,0 +1,16 @@ +CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable $(CPU_FLAGS) +CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS) +LDFLAGS += -shared +TARGET = libfiropow.so + +OBJECTS = ethash/ethash.o keccak/keccak.o keccak/keccakf800.o keccak/keccakf1600.o ethash/managed.o ethash/primes.o ethash/progpow.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libfiropow/attributes.h b/src/Native/libfiropow/attributes.h new file mode 100644 index 000000000..83be231f0 --- /dev/null +++ b/src/Native/libfiropow/attributes.h @@ -0,0 +1,33 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +/** inline */ +#if _MSC_VER || __STDC_VERSION__ +#define INLINE inline +#else +#define INLINE +#endif + +/** [[always_inline]] */ +#if _MSC_VER +#define ALWAYS_INLINE __forceinline +#elif defined(__has_attribute) && __STDC_VERSION__ +#if __has_attribute(always_inline) +#define ALWAYS_INLINE __attribute__((always_inline)) +#endif +#endif +#if !defined(ALWAYS_INLINE) +#define ALWAYS_INLINE +#endif + +/** [[no_sanitize()]] */ +#if __clang__ +#define NO_SANITIZE(sanitizer) \ + __attribute__((no_sanitize(sanitizer))) +#else +#define NO_SANITIZE(sanitizer) +#endif diff --git a/src/Native/libfiropow/dllmain.cpp b/src/Native/libfiropow/dllmain.cpp new file mode 100644 index 000000000..69b58914b --- /dev/null +++ b/src/Native/libfiropow/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/src/Native/libfiropow/ethash/CMakeLists.txt b/src/Native/libfiropow/ethash/CMakeLists.txt new file mode 100644 index 000000000..1eefc3f24 --- /dev/null +++ b/src/Native/libfiropow/ethash/CMakeLists.txt @@ -0,0 +1,37 @@ +# ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +# Copyright 2018-2019 Pawel Bylica. +# Licensed under the Apache License, Version 2.0. + +include(GNUInstallDirs) + +add_library( + ethash SHARED + bit_manipulation.h + builtins.h + endianness.hpp + ${include_dir}/ethash/ethash.h + ${include_dir}/ethash/ethash.hpp + ethash-internal.hpp + ethash.cpp + ${include_dir}/ethash/hash_types.h + managed.cpp + kiss99.hpp + primes.h + primes.c + ${include_dir}/ethash/progpow.hpp + progpow.cpp +) +set_property(TARGET ethash PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_link_libraries(ethash PRIVATE keccak) +target_include_directories(ethash PUBLIC $$) +if(CABLE_COMPILER_GNULIKE AND NOT SANITIZE MATCHES undefined) + target_compile_options(ethash PRIVATE $<$:-fno-rtti>) +endif() + +install( + TARGETS ethash + EXPORT ethashTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/src/Native/libfiropow/ethash/bit_manipulation.h b/src/Native/libfiropow/ethash/bit_manipulation.h new file mode 100644 index 000000000..b88bfdaab --- /dev/null +++ b/src/Native/libfiropow/ethash/bit_manipulation.h @@ -0,0 +1,81 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include "builtins.h" +#include "../support/attributes.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline uint32_t rotl32(uint32_t n, unsigned int c) +{ + const unsigned int mask = 31; + + c &= mask; + unsigned int neg_c = (unsigned int)(-(int)c); + return (n << c) | (n >> (neg_c & mask)); +} + +static inline uint32_t rotr32(uint32_t n, unsigned int c) +{ + const unsigned int mask = 31; + + c &= mask; + unsigned int neg_c = (unsigned int)(-(int)c); + return (n >> c) | (n << (neg_c & mask)); +} + +static inline uint32_t clz32(uint32_t x) +{ + return x ? (uint32_t)__builtin_clz(x) : 32; +} + +static inline uint32_t popcount32(uint32_t x) +{ + return (uint32_t)__builtin_popcount(x); +} + +static inline uint32_t mul_hi32(uint32_t x, uint32_t y) +{ + return (uint32_t)(((uint64_t)x * (uint64_t)y) >> 32); +} + + +/** FNV 32-bit prime. */ +static const uint32_t fnv_prime = 0x01000193; + +/** FNV 32-bit offset basis. */ +static const uint32_t fnv_offset_basis = 0x811c9dc5; + +/** + * The implementation of FNV-1 hash. + * + * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash. + */ +NO_SANITIZE("unsigned-integer-overflow") +static inline uint32_t fnv1(uint32_t u, uint32_t v) noexcept +{ + return (u * fnv_prime) ^ v; +} + +/** + * The implementation of FNV-1a hash. + * + * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash. + */ +NO_SANITIZE("unsigned-integer-overflow") +static inline uint32_t fnv1a(uint32_t u, uint32_t v) noexcept +{ + return (u ^ v) * fnv_prime; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libfiropow/ethash/builtins.h b/src/Native/libfiropow/ethash/builtins.h new file mode 100644 index 000000000..0c43188ad --- /dev/null +++ b/src/Native/libfiropow/ethash/builtins.h @@ -0,0 +1,43 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +/** + * @file + * Implementation of GCC/clang builtins for MSVC compiler. + */ + +#pragma once + +#ifdef _MSC_VER +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns the number of leading 0-bits in `x`, starting at the most significant bit position. + * If `x` is 0, the result is undefined. + */ +static inline int __builtin_clz(unsigned int x) +{ + unsigned long most_significant_bit; + _BitScanReverse(&most_significant_bit, x); + return 31 - (int)most_significant_bit; +} + +/** + * Returns the number of 1-bits in `x`. + */ +static inline int __builtin_popcount(unsigned int x) +{ + return (int)__popcnt(x); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Native/libfiropow/ethash/endianness.hpp b/src/Native/libfiropow/ethash/endianness.hpp new file mode 100644 index 000000000..3426f4689 --- /dev/null +++ b/src/Native/libfiropow/ethash/endianness.hpp @@ -0,0 +1,97 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +/// @file +/// This file contains helper functions to handle big-endian architectures. +/// The Ethash algorithm is naturally defined for little-endian architectures +/// so for those the helpers are just no-op empty functions. +/// For big-endian architectures we need 32-bit and 64-bit byte swapping in +/// some places. + +#pragma once + +#if _WIN32 + +#include + +#define bswap32 _byteswap_ulong +#define bswap64 _byteswap_uint64 + +// On Windows assume little endian. +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN + +#elif __APPLE__ + +#include + +#define bswap32 __builtin_bswap32 +#define bswap64 __builtin_bswap64 + +#else + +#include + +#define bswap32 __builtin_bswap32 +#define bswap64 __builtin_bswap64 + +#endif + +namespace ethash +{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + +struct le +{ + static uint32_t uint32(uint32_t x) noexcept { return x; } + static uint64_t uint64(uint64_t x) noexcept { return x; } + + static const hash1024& uint32s(const hash1024& h) noexcept { return h; } + static const hash512& uint32s(const hash512& h) noexcept { return h; } + static const hash256& uint32s(const hash256& h) noexcept { return h; } +}; + +struct be +{ + static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); } +}; + + +#elif __BYTE_ORDER == __BIG_ENDIAN + +struct le +{ + static uint32_t uint32(uint32_t x) noexcept { return bswap32(x); } + static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); } + + static hash1024 uint32s(hash1024 h) noexcept + { + for (auto& w : h.word32s) + w = uint32(w); + return h; + } + + static hash512 uint32s(hash512 h) noexcept + { + for (auto& w : h.word32s) + w = uint32(w); + return h; + } + + static hash256 uint32s(hash256 h) noexcept + { + for (auto& w : h.word32s) + w = uint32(w); + return h; + } +}; + +struct be +{ + static uint64_t uint64(uint64_t x) noexcept { return x; } +}; + +#endif +} // namespace ethash diff --git a/src/Native/libfiropow/ethash/ethash-internal.hpp b/src/Native/libfiropow/ethash/ethash-internal.hpp new file mode 100644 index 000000000..1d4ccd979 --- /dev/null +++ b/src/Native/libfiropow/ethash/ethash-internal.hpp @@ -0,0 +1,68 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +/// @file +/// Contains declarations of internal ethash functions to allow them to be +/// unit-tested. + +#pragma once + +#include "ethash.hpp" + +#include "endianness.hpp" + +#include +#include + +extern "C" struct ethash_epoch_context_full : ethash_epoch_context +{ + ethash_hash1024* full_dataset; + + constexpr ethash_epoch_context_full(int epoch, int light_num_items, + const ethash_hash512* light, const uint32_t* l1, int dataset_num_items, + ethash_hash1024* dataset) noexcept + : ethash_epoch_context{epoch, light_num_items, light, l1, dataset_num_items}, + full_dataset{dataset} + {} +}; + +namespace ethash +{ +inline bool is_less_or_equal(const hash256& a, const hash256& b) noexcept +{ + for (size_t i = 0; i < (sizeof(a) / sizeof(a.word64s[0])); ++i) + { + if (be::uint64(a.word64s[i]) > be::uint64(b.word64s[i])) + return false; + if (be::uint64(a.word64s[i]) < be::uint64(b.word64s[i])) + return true; + } + return true; +} + +inline bool is_equal(const hash256& a, const hash256& b) noexcept +{ + return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0; +} + +void build_light_cache(hash512 cache[], int num_items, const hash256& seed) noexcept; + +hash512 calculate_dataset_item_512(const epoch_context& context, int64_t index) noexcept; +hash1024 calculate_dataset_item_1024(const epoch_context& context, uint32_t index) noexcept; +hash2048 calculate_dataset_item_2048(const epoch_context& context, uint32_t index) noexcept; + +namespace generic +{ +using hash_fn_512 = hash512 (*)(const uint8_t* data, size_t size); +using build_light_cache_fn = void (*)(hash512 cache[], int num_items, const hash256& seed); + +void build_light_cache( + hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256& seed) noexcept; + +epoch_context_full* create_epoch_context( + build_light_cache_fn build_fn, int epoch_number, bool full) noexcept; + +} // namespace generic + +} // namespace ethash diff --git a/src/Native/libfiropow/ethash/ethash.cpp b/src/Native/libfiropow/ethash/ethash.cpp new file mode 100644 index 000000000..fce16c747 --- /dev/null +++ b/src/Native/libfiropow/ethash/ethash.cpp @@ -0,0 +1,443 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +#include "hash_types.hpp" + +#include "../attributes.h" +#include "bit_manipulation.h" +#include "endianness.hpp" +#include "ethash-internal.hpp" +#include "primes.h" + +#include "keccak.hpp" +#include "progpow.hpp" + +#include +#include +#include +#include + +namespace ethash +{ + // Internal constants: + constexpr static int light_cache_init_size = 1 << 24; + constexpr static int light_cache_growth = 1 << 17; + constexpr static int light_cache_rounds = 3; + constexpr static int full_dataset_init_size = (1 << 30) + (1 << 29); // 1.5GB == 1536 MB + constexpr static int full_dataset_growth = 1 << 23; + constexpr static int full_dataset_item_parents = 512; + + // Verify constants: + static_assert(sizeof(hash512) == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); + static_assert(sizeof(hash1024) == ETHASH_FULL_DATASET_ITEM_SIZE, ""); + static_assert(light_cache_item_size == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); + static_assert(full_dataset_item_size == ETHASH_FULL_DATASET_ITEM_SIZE, ""); + + namespace + { + using ::fnv1; + + inline hash512 fnv1(const hash512 &u, const hash512 &v) noexcept + { + hash512 r; + for (size_t i = 0; i < sizeof(r) / sizeof(r.word32s[0]); ++i) + r.word32s[i] = fnv1(u.word32s[i], v.word32s[i]); + return r; + } + + inline hash512 bitwise_xor(const hash512 &x, const hash512 &y) noexcept + { + hash512 z; + for (size_t i = 0; i < sizeof(z) / sizeof(z.word64s[0]); ++i) + z.word64s[i] = x.word64s[i] ^ y.word64s[i]; + return z; + } + } // namespace + + int find_epoch_number(const hash256 &seed) noexcept + { + static constexpr int num_tries = 30000; // Divisible by 16. + + // Thread-local cache of the last search. + static thread_local int cached_epoch_number = 0; + static thread_local hash256 cached_seed = {}; + + // Load from memory once (memory will be clobbered by keccak256()). + const uint32_t seed_part = seed.word32s[0]; + const int e = cached_epoch_number; + hash256 s = cached_seed; + + if (s.word32s[0] == seed_part) + return e; + + // Try the next seed, will match for sequential epoch access. + s = keccak256(s); + if (s.word32s[0] == seed_part) + { + cached_seed = s; + cached_epoch_number = e + 1; + return e + 1; + } + + // Search for matching seed starting from epoch 0. + s = {}; + for (int i = 0; i < num_tries; ++i) + { + if (s.word32s[0] == seed_part) + { + cached_seed = s; + cached_epoch_number = i; + return i; + } + + s = keccak256(s); + } + + return -1; + } + + namespace generic + { + void build_light_cache( + hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256 &seed) noexcept + { + hash512 item = hash_fn(seed.bytes, sizeof(seed)); + cache[0] = item; + for (int i = 1; i < num_items; ++i) + { + item = hash_fn(item.bytes, sizeof(item)); + cache[i] = item; + } + + for (int q = 0; q < light_cache_rounds; ++q) + { + for (int i = 0; i < num_items; ++i) + { + const uint32_t index_limit = static_cast(num_items); + + // Fist index: 4 first bytes of the item as little-endian integer. + const uint32_t t = le::uint32(cache[i].word32s[0]); + const uint32_t v = t % index_limit; + + // Second index. + const uint32_t w = static_cast(num_items + (i - 1)) % index_limit; + + const hash512 x = bitwise_xor(cache[v], cache[w]); + cache[i] = hash_fn(x.bytes, sizeof(x)); + } + } + } + + epoch_context_full *create_epoch_context( + build_light_cache_fn build_fn, int epoch_number, bool full) noexcept + { + static_assert(sizeof(epoch_context_full) < sizeof(hash512), "epoch_context too big"); + static constexpr size_t context_alloc_size = sizeof(hash512); + + const int light_cache_num_items = calculate_light_cache_num_items(epoch_number); + const int full_dataset_num_items = calculate_full_dataset_num_items(epoch_number); + const size_t light_cache_size = get_light_cache_size(light_cache_num_items); + const size_t full_dataset_size = + full ? static_cast(full_dataset_num_items) * sizeof(hash1024) : progpow::l1_cache_size; + + const size_t alloc_size = context_alloc_size + light_cache_size + full_dataset_size; + + char *const alloc_data = static_cast(std::calloc(1, alloc_size)); + if (!alloc_data) + return nullptr; // Signal out-of-memory by returning null pointer. + + hash512 *const light_cache = reinterpret_cast(alloc_data + context_alloc_size); + const hash256 epoch_seed = calculate_epoch_seed(epoch_number); + build_fn(light_cache, light_cache_num_items, epoch_seed); + + uint32_t *const l1_cache = + reinterpret_cast(alloc_data + context_alloc_size + light_cache_size); + + hash1024 *full_dataset = full ? reinterpret_cast(l1_cache) : nullptr; + + epoch_context_full *const context = new (alloc_data) epoch_context_full{ + epoch_number, + light_cache_num_items, + light_cache, + l1_cache, + full_dataset_num_items, + full_dataset, + }; + + auto *full_dataset_2048 = reinterpret_cast(l1_cache); + for (uint32_t i = 0; i < progpow::l1_cache_size / sizeof(full_dataset_2048[0]); ++i) + full_dataset_2048[i] = calculate_dataset_item_2048(*context, i); + return context; + } + } // namespace generic + + void build_light_cache(hash512 cache[], int num_items, const hash256 &seed) noexcept + { + return generic::build_light_cache(keccak512, cache, num_items, seed); + } + + struct item_state + { + const hash512 *const cache; + const int64_t num_cache_items; + const uint32_t seed; + + hash512 mix; + + ALWAYS_INLINE item_state(const epoch_context &context, int64_t index) noexcept + : cache{context.light_cache}, + num_cache_items{context.light_cache_num_items}, + seed{static_cast(index)} + { + mix = cache[index % num_cache_items]; + mix.word32s[0] ^= le::uint32(seed); + mix = le::uint32s(keccak512(mix)); + } + + ALWAYS_INLINE void update(uint32_t round) noexcept + { + static constexpr size_t num_words = sizeof(mix) / sizeof(uint32_t); + const uint32_t t = fnv1(seed ^ round, mix.word32s[round % num_words]); + const int64_t parent_index = t % num_cache_items; + mix = fnv1(mix, le::uint32s(cache[parent_index])); + } + + ALWAYS_INLINE hash512 final() noexcept { return keccak512(le::uint32s(mix)); } + }; + + hash512 calculate_dataset_item_512(const epoch_context &context, int64_t index) noexcept + { + item_state item0{context, index}; + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + item0.update(j); + return item0.final(); + } + + /// Calculates a full dataset item + /// + /// This consist of two 512-bit items produced by calculate_dataset_item_partial(). + /// Here the computation is done interleaved for better performance. + hash1024 calculate_dataset_item_1024(const epoch_context &context, uint32_t index) noexcept + { + item_state item0{context, int64_t(index) * 2}; + item_state item1{context, int64_t(index) * 2 + 1}; + + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + { + item0.update(j); + item1.update(j); + } + + return hash1024{{item0.final(), item1.final()}}; + } + + hash2048 calculate_dataset_item_2048(const epoch_context &context, uint32_t index) noexcept + { + item_state item0{context, int64_t(index) * 4}; + item_state item1{context, int64_t(index) * 4 + 1}; + item_state item2{context, int64_t(index) * 4 + 2}; + item_state item3{context, int64_t(index) * 4 + 3}; + + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + { + item0.update(j); + item1.update(j); + item2.update(j); + item3.update(j); + } + + return hash2048{{item0.final(), item1.final(), item2.final(), item3.final()}}; + } + + namespace + { + using lookup_fn = hash1024 (*)(const epoch_context &, uint32_t); + + inline hash512 hash_seed(const hash256 &header_hash, uint64_t nonce) noexcept + { + nonce = le::uint64(nonce); + uint8_t init_data[sizeof(header_hash) + sizeof(nonce)]; + std::memcpy(&init_data[0], &header_hash, sizeof(header_hash)); + std::memcpy(&init_data[sizeof(header_hash)], &nonce, sizeof(nonce)); + + return keccak512(init_data, sizeof(init_data)); + } + + inline hash256 hash_final(const hash512 &seed, const hash256 &mix_hash) + { + uint8_t final_data[sizeof(seed) + sizeof(mix_hash)]; + std::memcpy(&final_data[0], seed.bytes, sizeof(seed)); + std::memcpy(&final_data[sizeof(seed)], mix_hash.bytes, sizeof(mix_hash)); + return keccak256(final_data, sizeof(final_data)); + } + + inline hash256 hash_kernel( + const epoch_context &context, const hash512 &seed, lookup_fn lookup) noexcept + { + static constexpr size_t num_words = sizeof(hash1024) / sizeof(uint32_t); + const uint32_t index_limit = static_cast(context.full_dataset_num_items); + const uint32_t seed_init = le::uint32(seed.word32s[0]); + + hash1024 mix{{le::uint32s(seed), le::uint32s(seed)}}; + + for (uint32_t i = 0; i < num_dataset_accesses; ++i) + { + const uint32_t p = fnv1(i ^ seed_init, mix.word32s[i % num_words]) % index_limit; + const hash1024 newdata = le::uint32s(lookup(context, p)); + + for (size_t j = 0; j < num_words; ++j) + mix.word32s[j] = fnv1(mix.word32s[j], newdata.word32s[j]); + } + + hash256 mix_hash; + for (size_t i = 0; i < num_words; i += 4) + { + const uint32_t h1 = fnv1(mix.word32s[i], mix.word32s[i + 1]); + const uint32_t h2 = fnv1(h1, mix.word32s[i + 2]); + const uint32_t h3 = fnv1(h2, mix.word32s[i + 3]); + mix_hash.word32s[i / 4] = h3; + } + + return le::uint32s(mix_hash); + } + } // namespace + + result hash(const epoch_context_full &context, const hash256 &header_hash, uint64_t nonce) noexcept + { + static const auto lazy_lookup = [](const epoch_context &ctx, uint32_t index) noexcept + { + auto full_dataset = static_cast(ctx).full_dataset; + hash1024 &item = full_dataset[index]; + if (item.word64s[0] == 0) + { + // TODO: Copy elision here makes it thread-safe? + item = calculate_dataset_item_1024(ctx, index); + } + + return item; + }; + + const hash512 seed = hash_seed(header_hash, nonce); + const hash256 mix_hash = hash_kernel(context, seed, lazy_lookup); + return {hash_final(seed, mix_hash), mix_hash}; + } + + search_result search_light(const epoch_context &context, const hash256 &header_hash, + const hash256 &boundary, uint64_t start_nonce, size_t iterations) noexcept + { + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; + } + + search_result search(const epoch_context_full &context, const hash256 &header_hash, + const hash256 &boundary, uint64_t start_nonce, size_t iterations) noexcept + { + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; + } +} // namespace ethash + +using namespace ethash; + +extern "C" +{ + + ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) noexcept + { + ethash_hash256 epoch_seed = {}; + for (int i = 0; i < epoch_number; ++i) + epoch_seed = ethash_keccak256_32(epoch_seed.bytes); + return epoch_seed; + } + + int ethash_calculate_light_cache_num_items(int epoch_number) noexcept + { + static constexpr int item_size = sizeof(hash512); + static constexpr int num_items_init = light_cache_init_size / item_size; + static constexpr int num_items_growth = light_cache_growth / item_size; + static_assert( + light_cache_init_size % item_size == 0, "light_cache_init_size not multiple of item size"); + static_assert( + light_cache_growth % item_size == 0, "light_cache_growth not multiple of item size"); + + int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; + int num_items = ethash_find_largest_prime(num_items_upper_bound); + return num_items; + } + + int ethash_calculate_full_dataset_num_items(int epoch_number) noexcept + { + static constexpr int item_size = sizeof(hash1024); + static constexpr int num_items_init = full_dataset_init_size / item_size; + static constexpr int num_items_growth = full_dataset_growth / item_size; + static_assert(full_dataset_init_size % item_size == 0, + "full_dataset_init_size not multiple of item size"); + static_assert( + full_dataset_growth % item_size == 0, "full_dataset_growth not multiple of item size"); + + int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; + int num_items = ethash_find_largest_prime(num_items_upper_bound); + return num_items; + } + + epoch_context *ethash_create_epoch_context(int epoch_number) noexcept + { + return generic::create_epoch_context(build_light_cache, epoch_number, false); + } + + epoch_context_full *ethash_create_epoch_context_full(int epoch_number) noexcept + { + return generic::create_epoch_context(build_light_cache, epoch_number, true); + } + + void ethash_destroy_epoch_context_full(epoch_context_full *context) noexcept + { + ethash_destroy_epoch_context(context); + } + + void ethash_destroy_epoch_context(epoch_context *context) noexcept + { + context->~epoch_context(); + std::free(context); + } + + ethash_result ethash_hash( + const epoch_context *context, const hash256 *header_hash, uint64_t nonce) noexcept + { + const hash512 seed = hash_seed(*header_hash, nonce); + const hash256 mix_hash = hash_kernel(*context, seed, calculate_dataset_item_1024); + return {hash_final(seed, mix_hash), mix_hash}; + } + + bool ethash_verify_final_hash(const hash256 *header_hash, const hash256 *mix_hash, uint64_t nonce, + const hash256 *boundary) noexcept + { + const hash512 seed = hash_seed(*header_hash, nonce); + return is_less_or_equal(hash_final(seed, *mix_hash), *boundary); + } + + bool ethash_verify(const epoch_context *context, const hash256 *header_hash, + const hash256 *mix_hash, uint64_t nonce, const hash256 *boundary) noexcept + { + const hash512 seed = hash_seed(*header_hash, nonce); + if (!is_less_or_equal(hash_final(seed, *mix_hash), *boundary)) + return false; + + const hash256 expected_mix_hash = hash_kernel(*context, seed, calculate_dataset_item_1024); + return is_equal(expected_mix_hash, *mix_hash); + } + +} // extern "C" diff --git a/src/Native/libfiropow/ethash/ethash.h b/src/Native/libfiropow/ethash/ethash.h new file mode 100644 index 000000000..e570988c1 --- /dev/null +++ b/src/Native/libfiropow/ethash/ethash.h @@ -0,0 +1,138 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include "hash_types.h" + +#include +#include + +#if defined(_MSC_VER) +// Microsoft +#define EXPORT __declspec(dllexport) +#define IMPORT __declspec(dllimport) +#elif defined(__GNUC__) +// GCC +#define EXPORT __attribute__((visibility("default"))) +#define IMPORT +#else +// do nothing and hope for the best? +#define EXPORT +#define IMPORT +#pragma warning Unknown dynamic link import / export semantics. +#endif + +#ifdef __cplusplus +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * The Ethash algorithm revision implemented as specified in the Ethash spec + * https://github.com/ethereum/wiki/wiki/Ethash. + */ +#define ETHASH_REVISION "23" + +#define ETHASH_EPOCH_LENGTH 1300 +#define ETHASH_LIGHT_CACHE_ITEM_SIZE 64 +#define ETHASH_FULL_DATASET_ITEM_SIZE 128 +#define ETHASH_NUM_DATASET_ACCESSES 64 + + struct ethash_epoch_context + { + const int epoch_number; + const int light_cache_num_items; + const union ethash_hash512 *const light_cache; + const uint32_t *const l1_cache; + const int full_dataset_num_items; + }; + + struct ethash_epoch_context_full; + + struct ethash_result + { + union ethash_hash256 final_hash; + union ethash_hash256 mix_hash; + }; + + /** + * Calculates the number of items in the light cache for given epoch. + * + * This function will search for a prime number matching the criteria given + * by the Ethash so the execution time is not constant. It takes ~ 0.01 ms. + * + * @param epoch_number The epoch number. + * @return The number items in the light cache. + */ + int ethash_calculate_light_cache_num_items(int epoch_number) NOEXCEPT; + + /** + * Calculates the number of items in the full dataset for given epoch. + * + * This function will search for a prime number matching the criteria given + * by the Ethash so the execution time is not constant. It takes ~ 0.05 ms. + * + * @param epoch_number The epoch number. + * @return The number items in the full dataset. + */ + int ethash_calculate_full_dataset_num_items(int epoch_number) NOEXCEPT; + + /** + * Calculates the epoch seed hash. + * @param epoch_number The epoch number. + * @return The epoch seed hash. + */ + EXPORT union ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) NOEXCEPT; + + EXPORT struct ethash_epoch_context *ethash_create_epoch_context(int epoch_number) NOEXCEPT; + + /** + * Creates the epoch context with the full dataset initialized. + * + * The memory for the full dataset is only allocated and marked as "not-generated". + * The items of the full dataset are generated on the fly when hit for the first time. + * + * The memory allocated in the context MUST be freed with ethash_destroy_epoch_context_full(). + * + * @param epoch_number The epoch number. + * @return Pointer to the context or null in case of memory allocation failure. + */ + EXPORT struct ethash_epoch_context_full *ethash_create_epoch_context_full(int epoch_number) NOEXCEPT; + + EXPORT void ethash_destroy_epoch_context(struct ethash_epoch_context *context) NOEXCEPT; + + EXPORT void ethash_destroy_epoch_context_full(struct ethash_epoch_context_full *context) NOEXCEPT; + + /** + * Get global shared epoch context. + */ + const struct ethash_epoch_context *ethash_get_global_epoch_context(int epoch_number) NOEXCEPT; + + /** + * Get global shared epoch context with full dataset initialized. + */ + const struct ethash_epoch_context_full *ethash_get_global_epoch_context_full( + int epoch_number) NOEXCEPT; + + struct ethash_result ethash_hash(const struct ethash_epoch_context *context, + const union ethash_hash256 *header_hash, uint64_t nonce) NOEXCEPT; + + bool ethash_verify(const struct ethash_epoch_context *context, + const union ethash_hash256 *header_hash, const union ethash_hash256 *mix_hash, uint64_t nonce, + const union ethash_hash256 *boundary) NOEXCEPT; + bool ethash_verify_final_hash(const union ethash_hash256 *header_hash, + const union ethash_hash256 *mix_hash, uint64_t nonce, + const union ethash_hash256 *boundary) NOEXCEPT; + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libfiropow/ethash/ethash.hpp b/src/Native/libfiropow/ethash/ethash.hpp new file mode 100644 index 000000000..835a3b731 --- /dev/null +++ b/src/Native/libfiropow/ethash/ethash.hpp @@ -0,0 +1,172 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +/// @file +/// +/// API design decisions: +/// +/// 1. Signed integer type is used whenever the size of the type is not +/// restricted by the Ethash specification. +/// See http://www.aristeia.com/Papers/C++ReportColumns/sep95.pdf. +/// See https://stackoverflow.com/questions/10168079/why-is-size-t-unsigned/. +/// See https://github.com/Microsoft/GSL/issues/171. + +#pragma once + +#include "ethash.h" +#include "hash_types.hpp" + +#include +#include +#include + +namespace ethash +{ +constexpr auto revision = ETHASH_REVISION; + +static constexpr int epoch_length = ETHASH_EPOCH_LENGTH; +static constexpr int light_cache_item_size = ETHASH_LIGHT_CACHE_ITEM_SIZE; +static constexpr int full_dataset_item_size = ETHASH_FULL_DATASET_ITEM_SIZE; +static constexpr int num_dataset_accesses = ETHASH_NUM_DATASET_ACCESSES; + +using epoch_context = ethash_epoch_context; +using epoch_context_full = ethash_epoch_context_full; + +using result = ethash_result; + +/// Constructs a 256-bit hash from an array of bytes. +/// +/// @param bytes A pointer to array of at least 32 bytes. +/// @return The constructed hash. +inline hash256 hash256_from_bytes(const uint8_t bytes[32]) noexcept +{ + hash256 h; + std::memcpy(&h, bytes, sizeof(h)); + return h; +} + +struct search_result +{ + bool solution_found = false; + uint64_t nonce = 0; + hash256 final_hash = {}; + hash256 mix_hash = {}; + + search_result() noexcept = default; + + search_result(result res, uint64_t n) noexcept + : solution_found(true), nonce(n), final_hash(res.final_hash), mix_hash(res.mix_hash) + {} +}; + + +/// Alias for ethash_calculate_light_cache_num_items(). +static constexpr auto calculate_light_cache_num_items = ethash_calculate_light_cache_num_items; + +/// Alias for ethash_calculate_full_dataset_num_items(). +static constexpr auto calculate_full_dataset_num_items = ethash_calculate_full_dataset_num_items; + +/// Alias for ethash_calculate_epoch_seed(). +static constexpr auto calculate_epoch_seed = ethash_calculate_epoch_seed; + + +/// Calculates the epoch number out of the block number. +inline constexpr int get_epoch_number(int block_number) noexcept +{ + return block_number / epoch_length; +} + +/** + * Coverts the number of items of a light cache to size in bytes. + * + * @param num_items The number of items in the light cache. + * @return The size of the light cache in bytes. + */ +inline constexpr size_t get_light_cache_size(int num_items) noexcept +{ + return static_cast(num_items) * light_cache_item_size; +} + +/** + * Coverts the number of items of a full dataset to size in bytes. + * + * @param num_items The number of items in the full dataset. + * @return The size of the full dataset in bytes. + */ +inline constexpr uint64_t get_full_dataset_size(int num_items) noexcept +{ + return static_cast(num_items) * full_dataset_item_size; +} + +/// Owned unique pointer to an epoch context. +using epoch_context_ptr = std::unique_ptr; + +using epoch_context_full_ptr = + std::unique_ptr; + +/// Creates Ethash epoch context. +/// +/// This is a wrapper for ethash_create_epoch_number C function that returns +/// the context as a smart pointer which handles the destruction of the context. +inline epoch_context_ptr create_epoch_context(int epoch_number) noexcept +{ + return {ethash_create_epoch_context(epoch_number), ethash_destroy_epoch_context}; +} + +inline epoch_context_full_ptr create_epoch_context_full(int epoch_number) noexcept +{ + return {ethash_create_epoch_context_full(epoch_number), ethash_destroy_epoch_context_full}; +} + + +inline result hash( + const epoch_context& context, const hash256& header_hash, uint64_t nonce) noexcept +{ + return ethash_hash(&context, &header_hash, nonce); +} + +result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept; + +inline bool verify_final_hash(const hash256& header_hash, const hash256& mix_hash, uint64_t nonce, + const hash256& boundary) noexcept +{ + return ethash_verify_final_hash(&header_hash, &mix_hash, nonce, &boundary); +} + +inline bool verify(const epoch_context& context, const hash256& header_hash, const hash256& mix_hash, + uint64_t nonce, const hash256& boundary) noexcept +{ + return ethash_verify(&context, &header_hash, &mix_hash, nonce, &boundary); +} + +search_result search_light(const epoch_context& context, const hash256& header_hash, + const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept; + +search_result search(const epoch_context_full& context, const hash256& header_hash, + const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept; + + +/// Tries to find the epoch number matching the given seed hash. +/// +/// Mining pool protocols (many variants of stratum and "getwork") send out +/// seed hash instead of epoch number to workers. This function tries to recover +/// the epoch number from this seed hash. +/// +/// @param seed Ethash seed hash. +/// @return The epoch number or -1 if not found. +int find_epoch_number(const hash256& seed) noexcept; + + +/// Get global shared epoch context. +inline const epoch_context& get_global_epoch_context(int epoch_number) noexcept +{ + return *ethash_get_global_epoch_context(epoch_number); +} + +/// Get global shared epoch context with full dataset initialized. +inline const epoch_context_full& get_global_epoch_context_full(int epoch_number) noexcept +{ + return *ethash_get_global_epoch_context_full(epoch_number); +} +} // namespace ethash diff --git a/src/Native/libfiropow/ethash/hash_types.h b/src/Native/libfiropow/ethash/hash_types.h new file mode 100644 index 000000000..bd9343686 --- /dev/null +++ b/src/Native/libfiropow/ethash/hash_types.h @@ -0,0 +1,50 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +union ethash_hash256 +{ + uint64_t word64s[4]; + uint32_t word32s[8]; + uint8_t bytes[32]; + char str[32]; +}; + +union ethash_hash512 +{ + uint64_t word64s[8]; + uint32_t word32s[16]; + uint8_t bytes[64]; + char str[64]; +}; + +union ethash_hash1024 +{ + union ethash_hash512 hash512s[2]; + uint64_t word64s[16]; + uint32_t word32s[32]; + uint8_t bytes[128]; + char str[128]; +}; + +union ethash_hash2048 +{ + union ethash_hash512 hash512s[4]; + uint64_t word64s[32]; + uint32_t word32s[64]; + uint8_t bytes[256]; + char str[256]; +}; + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libfiropow/ethash/hash_types.hpp b/src/Native/libfiropow/ethash/hash_types.hpp new file mode 100644 index 000000000..a31cff49f --- /dev/null +++ b/src/Native/libfiropow/ethash/hash_types.hpp @@ -0,0 +1,15 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +#pragma once + +#include "hash_types.h" + +namespace ethash +{ +using hash256 = ethash_hash256; +using hash512 = ethash_hash512; +using hash1024 = ethash_hash1024; +using hash2048 = ethash_hash2048; +} // namespace ethash diff --git a/src/Native/libfiropow/ethash/keccak.h b/src/Native/libfiropow/ethash/keccak.h new file mode 100644 index 000000000..79ef7c5cc --- /dev/null +++ b/src/Native/libfiropow/ethash/keccak.h @@ -0,0 +1,49 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include "hash_types.h" + +#include + +#ifdef __cplusplus +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The Keccak-f[1600] function. + * + * The implementation of the Keccak-f function with 1600-bit width of the permutation (b). + * The size of the state is also 1600 bit what gives 25 64-bit words. + * + * @param state The state of 25 64-bit words on which the permutation is to be performed. + */ +void ethash_keccakf1600(uint64_t state[25]) NOEXCEPT; + +/** + * The Keccak-f[800] function. + * + * The implementation of the Keccak-f function with 800-bit width of the permutation (b). + * The size of the state is also 800 bit what gives 25 32-bit words. + * + * @param state The state of 25 32-bit words on which the permutation is to be performed. + */ +void ethash_keccakf800(uint32_t state[25]) NOEXCEPT; + +union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) NOEXCEPT; +union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) NOEXCEPT; +union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) NOEXCEPT; +union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) NOEXCEPT; + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libfiropow/ethash/keccak.hpp b/src/Native/libfiropow/ethash/keccak.hpp new file mode 100644 index 000000000..974067922 --- /dev/null +++ b/src/Native/libfiropow/ethash/keccak.hpp @@ -0,0 +1,35 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +#pragma once + +#include "keccak.h" +#include "hash_types.hpp" + +namespace ethash +{ +inline hash256 keccak256(const uint8_t* data, size_t size) noexcept +{ + return ethash_keccak256(data, size); +} + +inline hash256 keccak256(const hash256& input) noexcept +{ + return ethash_keccak256_32(input.bytes); +} + +inline hash512 keccak512(const uint8_t* data, size_t size) noexcept +{ + return ethash_keccak512(data, size); +} + +inline hash512 keccak512(const hash512& input) noexcept +{ + return ethash_keccak512_64(input.bytes); +} + +static constexpr auto keccak256_32 = ethash_keccak256_32; +static constexpr auto keccak512_64 = ethash_keccak512_64; + +} // namespace ethash diff --git a/src/Native/libfiropow/ethash/kiss99.hpp b/src/Native/libfiropow/ethash/kiss99.hpp new file mode 100644 index 000000000..8332a7ce9 --- /dev/null +++ b/src/Native/libfiropow/ethash/kiss99.hpp @@ -0,0 +1,64 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include "../support/attributes.h" +#include + +/** + * KISS PRNG by the spec from 1999. + * + * The implementation of KISS pseudo-random number generator + * by the specification published on 21 Jan 1999 in + * http://www.cse.yorku.ca/~oz/marsaglia-rng.html. + * The KISS is not versioned so here we are using `kiss99` prefix to indicate + * the version from 1999. + * + * The specification uses `unsigned long` type with the intention for 32-bit + * values. Because in GCC/clang for 64-bit architectures `unsigned long` is + * 64-bit size type, here the explicit `uint32_t` type is used. + * + * @defgroup kiss99 KISS99 + * @{ + */ + +/** + * The KISS generator. + */ +class kiss99 +{ + uint32_t z = 362436069; + uint32_t w = 521288629; + uint32_t jsr = 123456789; + uint32_t jcong = 380116160; + +public: + /** Creates KISS generator state with default values provided by the specification. */ + kiss99() noexcept = default; + + /** Creates KISS generator state with provided init values.*/ + kiss99(uint32_t _z, uint32_t _w, uint32_t _jsr, uint32_t _jcong) noexcept + : z{_z}, w{_w}, jsr{_jsr}, jcong{_jcong} + {} + + /** Generates next number from the KISS generator. */ + NO_SANITIZE("unsigned-integer-overflow") + uint32_t operator()() noexcept + { + z = 36969 * (z & 0xffff) + (z >> 16); + w = 18000 * (w & 0xffff) + (w >> 16); + + jcong = 69069 * jcong + 1234567; + + jsr ^= (jsr << 17); + jsr ^= (jsr >> 13); + jsr ^= (jsr << 5); + + return (((z << 16) + w) ^ jcong) + jsr; + } +}; + +/** @} */ diff --git a/src/Native/libfiropow/ethash/managed.cpp b/src/Native/libfiropow/ethash/managed.cpp new file mode 100644 index 000000000..47dd49b8e --- /dev/null +++ b/src/Native/libfiropow/ethash/managed.cpp @@ -0,0 +1,99 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +#include "ethash-internal.hpp" + +#include +#include + +#if !defined(__has_cpp_attribute) +#define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(gnu::noinline) +#define ATTRIBUTE_NOINLINE [[gnu::noinline]] +#elif _MSC_VER +#define ATTRIBUTE_NOINLINE __declspec(noinline) +#else +#define ATTRIBUTE_NOINLINE +#endif + +using namespace ethash; + +namespace +{ +std::mutex shared_context_mutex; +std::shared_ptr shared_context; +thread_local std::shared_ptr thread_local_context; + +std::mutex shared_context_full_mutex; +std::shared_ptr shared_context_full; +thread_local std::shared_ptr thread_local_context_full; + +/// Update thread local epoch context. +/// +/// This function is on the slow path. It's separated to allow inlining the fast +/// path. +/// +/// @todo: Redesign to guarantee deallocation before new allocation. +ATTRIBUTE_NOINLINE +void update_local_context(int epoch_number) +{ + // Release the shared pointer of the obsoleted context. + thread_local_context.reset(); + + // Local context invalid, check the shared context. + std::lock_guard lock{shared_context_mutex}; + + if (!shared_context || shared_context->epoch_number != epoch_number) + { + // Release the shared pointer of the obsoleted context. + shared_context.reset(); + + // Build new context. + shared_context = create_epoch_context(epoch_number); + } + + thread_local_context = shared_context; +} + +ATTRIBUTE_NOINLINE +void update_local_context_full(int epoch_number) +{ + // Release the shared pointer of the obsoleted context. + thread_local_context_full.reset(); + + // Local context invalid, check the shared context. + std::lock_guard lock{shared_context_full_mutex}; + + if (!shared_context_full || shared_context_full->epoch_number != epoch_number) + { + // Release the shared pointer of the obsoleted context. + shared_context_full.reset(); + + // Build new context. + shared_context_full = create_epoch_context_full(epoch_number); + } + + thread_local_context_full = shared_context_full; +} +} // namespace + +const ethash_epoch_context* ethash_get_global_epoch_context(int epoch_number) noexcept +{ + // Check if local context matches epoch number. + if (!thread_local_context || thread_local_context->epoch_number != epoch_number) + update_local_context(epoch_number); + + return thread_local_context.get(); +} + +const ethash_epoch_context_full* ethash_get_global_epoch_context_full(int epoch_number) noexcept +{ + // Check if local context matches epoch number. + if (!thread_local_context_full || thread_local_context_full->epoch_number != epoch_number) + update_local_context_full(epoch_number); + + return thread_local_context_full.get(); +} diff --git a/src/Native/libfiropow/ethash/primes.c b/src/Native/libfiropow/ethash/primes.c new file mode 100644 index 000000000..e27a535e3 --- /dev/null +++ b/src/Native/libfiropow/ethash/primes.c @@ -0,0 +1,43 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#include "primes.h" + +/** Checks if the number is prime. Requires the number to be > 2 and odd. */ +static int is_odd_prime(int number) +{ + int d; + + /* Check factors up to sqrt(number). + To avoid computing sqrt, compare d*d <= number with 64-bit precision. */ + for (d = 3; (int64_t)d * (int64_t)d <= (int64_t)number; d += 2) + { + if (number % d == 0) + return 0; + } + + return 1; +} + +int ethash_find_largest_prime(int upper_bound) +{ + int n = upper_bound; + + if (n < 2) + return 0; + + if (n == 2) + return 2; + + /* If even number, skip it. */ + if (n % 2 == 0) + --n; + + /* Test descending odd numbers. */ + while (!is_odd_prime(n)) + n -= 2; + + return n; +} diff --git a/src/Native/libfiropow/ethash/primes.h b/src/Native/libfiropow/ethash/primes.h new file mode 100644 index 000000000..e37c532f2 --- /dev/null +++ b/src/Native/libfiropow/ethash/primes.h @@ -0,0 +1,25 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include "ethash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Finds the largest prime number not greater than the provided upper bound. + * + * @param upper_bound The upper bound. SHOULD be greater than 1. + * @return The largest prime number `p` such `p <= upper_bound`. + * In case `upper_bound <= 1`, returns 0. + */ +int ethash_find_largest_prime(int upper_bound) NOEXCEPT; + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libfiropow/ethash/progpow.cpp b/src/Native/libfiropow/ethash/progpow.cpp new file mode 100644 index 000000000..116620486 --- /dev/null +++ b/src/Native/libfiropow/ethash/progpow.cpp @@ -0,0 +1,414 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +#include "progpow.hpp" + +#include "bit_manipulation.h" +#include "endianness.hpp" +#include "ethash-internal.hpp" +#include "kiss99.hpp" +#include "keccak.hpp" + +#include + +namespace progpow +{ +namespace +{ + +/// ProgPoW mix RNG state. +/// +/// Encapsulates the state of the random number generator used in computing ProgPoW mix. +/// This includes the state of the KISS99 RNG and the precomputed random permutation of the +/// sequence of mix item indexes. +class mix_rng_state +{ +public: + inline explicit mix_rng_state(uint64_t seed) noexcept; + + uint32_t next_dst() noexcept { return dst_seq[(dst_counter++) % num_regs]; } + uint32_t next_src() noexcept { return src_seq[(src_counter++) % num_regs]; } + + kiss99 rng; + +private: + size_t dst_counter = 0; + std::array dst_seq; + size_t src_counter = 0; + std::array src_seq; +}; + +mix_rng_state::mix_rng_state(uint64_t seed) noexcept +{ + const auto seed_lo = static_cast(seed); + const auto seed_hi = static_cast(seed >> 32); + + const auto z = fnv1a(fnv_offset_basis, seed_lo); + const auto w = fnv1a(z, seed_hi); + const auto jsr = fnv1a(w, seed_lo); + const auto jcong = fnv1a(jsr, seed_hi); + + rng = kiss99{z, w, jsr, jcong}; + + // Create random permutations of mix destinations / sources. + // Uses Fisher-Yates shuffle. + for (uint32_t i = 0; i < num_regs; ++i) + { + dst_seq[i] = i; + src_seq[i] = i; + } + + for (uint32_t i = num_regs; i > 1; --i) + { + std::swap(dst_seq[i - 1], dst_seq[rng() % i]); + std::swap(src_seq[i - 1], src_seq[rng() % i]); + } +} + + +NO_SANITIZE("unsigned-integer-overflow") +inline uint32_t random_math(uint32_t a, uint32_t b, uint32_t selector) noexcept +{ + switch (selector % 11) + { + default: + case 0: + return a + b; + case 1: + return a * b; + case 2: + return mul_hi32(a, b); + case 3: + return std::min(a, b); + case 4: + return rotl32(a, b); + case 5: + return rotr32(a, b); + case 6: + return a & b; + case 7: + return a | b; + case 8: + return a ^ b; + case 9: + return clz32(a) + clz32(b); + case 10: + return popcount32(a) + popcount32(b); + } +} + +/// Merge data from `b` and `a`. +/// Assuming `a` has high entropy, only do ops that retain entropy even if `b` +/// has low entropy (i.e. do not do `a & b`). +NO_SANITIZE("unsigned-integer-overflow") +inline void random_merge(uint32_t& a, uint32_t b, uint32_t selector) noexcept +{ + const auto x = (selector >> 16) % 31 + 1; // Additional non-zero selector from higher bits. + switch (selector % 4) + { + case 0: + a = (a * 33) + b; + break; + case 1: + a = (a ^ b) * 33; + break; + case 2: + a = rotl32(a, x) ^ b; + break; + case 3: + a = rotr32(a, x) ^ b; + break; + } +} + +using lookup_fn = hash2048 (*)(const epoch_context&, uint32_t); + +using mix_array = std::array, num_lanes>; + +void round( + const epoch_context& context, uint32_t r, mix_array& mix, mix_rng_state state, lookup_fn lookup) +{ + const uint32_t num_items = static_cast(context.full_dataset_num_items / 2); + const uint32_t item_index = mix[r % num_lanes][0] % num_items; + const hash2048 item = lookup(context, item_index); + + constexpr size_t num_words_per_lane = sizeof(item) / (sizeof(uint32_t) * num_lanes); + constexpr int max_operations = + num_cache_accesses > num_math_operations ? num_cache_accesses : num_math_operations; + + // Process lanes. + for (int i = 0; i < max_operations; ++i) + { + if (i < num_cache_accesses) // Random access to cached memory. + { + const auto src = state.next_src(); + const auto dst = state.next_dst(); + const auto sel = state.rng(); + + for (size_t l = 0; l < num_lanes; ++l) + { + const size_t offset = mix[l][src] % l1_cache_num_items; + random_merge(mix[l][dst], le::uint32(context.l1_cache[offset]), sel); + } + } + if (i < num_math_operations) // Random math. + { + // Generate 2 unique source indexes. + const auto src_rnd = state.rng() % (num_regs * (num_regs - 1)); + const auto src1 = src_rnd % num_regs; // O <= src1 < num_regs + auto src2 = src_rnd / num_regs; // 0 <= src2 < num_regs - 1 + if (src2 >= src1) + ++src2; + + const auto sel1 = state.rng(); + const auto dst = state.next_dst(); + const auto sel2 = state.rng(); + + for (size_t l = 0; l < num_lanes; ++l) + { + const uint32_t data = random_math(mix[l][src1], mix[l][src2], sel1); + random_merge(mix[l][dst], data, sel2); + } + } + } + + // DAG access pattern. + uint32_t dsts[num_words_per_lane]; + uint32_t sels[num_words_per_lane]; + for (size_t i = 0; i < num_words_per_lane; ++i) + { + dsts[i] = i == 0 ? 0 : state.next_dst(); + sels[i] = state.rng(); + } + + // DAG access. + for (size_t l = 0; l < num_lanes; ++l) + { + const auto offset = ((l ^ r) % num_lanes) * num_words_per_lane; + for (size_t i = 0; i < num_words_per_lane; ++i) + { + const auto word = le::uint32(item.word32s[offset + i]); + random_merge(mix[l][dsts[i]], word, sels[i]); + } + } +} + +mix_array init_mix(uint64_t seed) +{ + const uint32_t z = fnv1a(fnv_offset_basis, static_cast(seed)); + const uint32_t w = fnv1a(z, static_cast(seed >> 32)); + + mix_array mix; + for (uint32_t l = 0; l < mix.size(); ++l) + { + const uint32_t jsr = fnv1a(w, l); + const uint32_t jcong = fnv1a(jsr, l); + kiss99 rng{z, w, jsr, jcong}; + + for (auto& row : mix[l]) + row = rng(); + } + return mix; +} + +hash256 hash_mix( + const epoch_context& context, int block_number, uint64_t seed, lookup_fn lookup) noexcept +{ + auto mix = init_mix(seed); + auto number = uint64_t(block_number / period_length); + mix_rng_state state{uint64_t(block_number / period_length)}; + + for (uint32_t i = 0; i < num_rounds; ++i) + round(context, i, mix, state, lookup); + + // Reduce mix data to a single per-lane result. + uint32_t lane_hash[num_lanes]; + for (size_t l = 0; l < num_lanes; ++l) + { + lane_hash[l] = fnv_offset_basis; + for (uint32_t i = 0; i < num_regs; ++i) + lane_hash[l] = fnv1a(lane_hash[l], mix[l][i]); + } + + // Reduce all lanes to a single 256-bit result. + static constexpr size_t num_words = sizeof(hash256) / sizeof(uint32_t); + hash256 mix_hash; + for (uint32_t& w : mix_hash.word32s) + w = fnv_offset_basis; + for (size_t l = 0; l < num_lanes; ++l) + mix_hash.word32s[l % num_words] = fnv1a(mix_hash.word32s[l % num_words], lane_hash[l]); + return le::uint32s(mix_hash); +} +} // namespace + +hash256 hash_seed(const hash256 *header_hash_ptr, uint64_t nonce) noexcept +{ + uint32_t state[25] = {0x0}; + nonce = le::uint64(nonce); + + for (int i = 0; i < 8; ++i) { + state[i] = le::uint32(header_hash_ptr->word32s[i]); + } + std::memcpy(&state[8], &nonce, sizeof(uint64_t)); + state[10] = 0x00000001; + state[18] = 0x80008081; + + ethash_keccakf800(state); + + hash256 output; + for (int i = 0; i < 8; ++i) + output.word32s[i] = le::uint32(state[i]); + return output; +} + +hash256 hash_final(const hash256& seed_hash, const hash256 *mix_hash_ptr) noexcept +{ + uint32_t state[25] = {0x0}; + std::memcpy(&state[0], seed_hash.bytes, sizeof(hash256)); + std::memcpy(&state[8], mix_hash_ptr, sizeof(hash256)); + state[17] = 0x00000001; + state[24] = 0x80008081; + + ethash_keccakf800(state); + hash256 final_hash; + std::memcpy(&final_hash, &state[0], sizeof(hash256)); + return final_hash; +} + +/*void hash_one(const epoch_context& context, int block_number, const hash256 *header_hash_ptr, + uint64_t nonce, hash256 *mix_out_ptr, hash256 *hash_out_ptr) noexcept +{ + const hash256 seed_hash = hash_seed(header_hash_ptr, nonce); + const uint64_t seed = seed_hash.word64s[0]; + hash_mix(context, block_number, seed, calculate_dataset_item_2048, mix_out_ptr); + hash_final(seed_hash, mix_out_ptr, hash_out_ptr); +}*/ + +result hashext(const epoch_context& context, int block_number, const hash256& header_hash, + uint64_t nonce, const hash256& mix_hash, const hash256& boundary1, const hash256& boundary2, int* retcode) noexcept +{ + const hash256 seed_hash = hash_seed((const hash256 *)&header_hash, nonce); + const uint64_t seed = seed_hash.word64s[0]; + const hash256 computed_mix_hash = hash_mix(context, block_number, seed, calculate_dataset_item_2048); + const hash256 computed_final_hash = hash_final(seed_hash, (const hash256 *)&computed_mix_hash); + + /* mod start */ + if (!is_less_or_equal(computed_final_hash, boundary1)) { + //if(boundary1 == boundary2) { + if(is_equal(boundary1, boundary2)) { + *retcode = 1; + return {computed_final_hash, mix_hash}; + } + else { + if (!is_less_or_equal(computed_final_hash, boundary2)) { + *retcode = 1; + return {computed_final_hash, mix_hash}; + } + } + } + + if(!is_equal(computed_mix_hash, mix_hash)) { + *retcode = 2; + return {computed_final_hash, mix_hash}; + } + /* mod end */ + *retcode = 0; + return {computed_final_hash, computed_mix_hash}; +} + +result hash(const epoch_context& context, int block_number, const hash256& header_hash, + uint64_t nonce) noexcept +{ + const hash256 seed_hash = hash_seed((const hash256 *)&header_hash, nonce); + const uint64_t seed = seed_hash.word64s[0]; + const hash256 computed_mix_hash = hash_mix(context, block_number, seed, calculate_dataset_item_2048); + const hash256 computed_final_hash = hash_final(seed_hash, (const hash256 *)&computed_mix_hash); + + return {computed_final_hash, computed_mix_hash}; +} + +result hash(const epoch_context_full& context, int block_number, const hash256& header_hash, + uint64_t nonce) noexcept +{ + static const auto lazy_lookup = [](const epoch_context& ctx, uint32_t index) noexcept + { + auto* full_dataset_1024 = static_cast(ctx).full_dataset; + auto* full_dataset_2048 = reinterpret_cast(full_dataset_1024); + hash2048& item = full_dataset_2048[index]; + if (item.word64s[0] == 0) + { + // TODO: Copy elision here makes it thread-safe? + item = calculate_dataset_item_2048(ctx, index); + } + + return item; + }; + + const hash256 seed_hash = hash_seed((const hash256 *)&header_hash, nonce); + const uint64_t seed = seed_hash.word64s[0]; + const hash256 computed_mix_hash = hash_mix(context, block_number, seed, lazy_lookup); + const hash256 computed_final_hash = hash_final(seed_hash, (const hash256 *)&computed_mix_hash); + + return {computed_final_hash, computed_mix_hash}; +} + +bool verify(const epoch_context& context, int block_number, const hash256& header_hash, + const hash256& mix_hash, uint64_t nonce, const hash256& boundary) noexcept +{ + const hash256 seed_hash = hash_seed((const hash256 *)&header_hash, nonce); + const uint64_t seed = seed_hash.word64s[0]; + const hash256 expected_mix_hash = hash_mix(context, block_number, seed, calculate_dataset_item_2048); + const hash256 computed_final_hash = hash_final(seed_hash, (const hash256 *)&expected_mix_hash); + + + if (!is_less_or_equal(computed_final_hash, boundary)) { + return false; + } + + return is_equal(expected_mix_hash, mix_hash); +} + +/*bool verify(const epoch_context& context, int block_number, const hash256 *header_hash_ptr, + const hash256 &mix_hash, uint64_t nonce, hash256 *hash_out_ptr) noexcept +{ + const hash256 seed_hash = hash_seed(header_hash_ptr, nonce); + const uint64_t seed = seed_hash.word64s[0]; + hash_final(seed_hash, &mix_hash, hash_out_ptr); + + // Check mixes match + hash256 expected_mix_hash; + hash_mix(context, block_number, seed, calculate_dataset_item_2048, (hash256*)&expected_mix_hash); + + return is_equal(expected_mix_hash, mix_hash); +}*/ + +search_result search_light(const epoch_context& context, int block_number, + const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, + size_t iterations) noexcept +{ + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, block_number, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; +} + +search_result search(const epoch_context_full& context, int block_number, + const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, + size_t iterations) noexcept +{ + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, block_number, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; +} + +} // namespace progpow diff --git a/src/Native/libfiropow/ethash/progpow.hpp b/src/Native/libfiropow/ethash/progpow.hpp new file mode 100644 index 000000000..ac6e4a304 --- /dev/null +++ b/src/Native/libfiropow/ethash/progpow.hpp @@ -0,0 +1,68 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018-2019 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +/// @file +/// +/// ProgPoW API +/// +/// This file provides the public API for ProgPoW as the Ethash API extension. + +#include "ethash.hpp" + +#if defined(_MSC_VER) +// Microsoft +#define EXPORT __declspec(dllexport) +#define IMPORT __declspec(dllimport) +#elif defined(__GNUC__) +// GCC +#define EXPORT __attribute__((visibility("default"))) +#define IMPORT +#else +// do nothing and hope for the best? +#define EXPORT +#define IMPORT +#pragma warning Unknown dynamic link import / export semantics. +#endif + +namespace progpow +{ + using namespace ethash; // Include ethash namespace. + + /// The ProgPoW algorithm revision implemented as specified in the spec + /// https://github.com/ifdefelse/ProgPOW#change-history. + constexpr auto revision = "0.9.4"; + + constexpr int period_length = 1; + constexpr uint32_t num_regs = 32; + constexpr size_t num_lanes = 16; + constexpr uint32_t num_rounds = 64; + constexpr int num_cache_accesses = 11; + constexpr int num_math_operations = 18; + constexpr size_t l1_cache_size = 16 * 1024; + constexpr size_t l1_cache_num_items = l1_cache_size / sizeof(uint32_t); + + result hashext(const epoch_context &context, int block_number, const hash256 &header_hash, + uint64_t nonce, const hash256 &mix_hash, const hash256 &boundary1, const hash256 &boundary2, int *retcode) noexcept; + + extern "C" EXPORT result hash(const epoch_context &context, int block_number, const hash256 &header_hash, + uint64_t nonce) noexcept; + + result hash(const epoch_context_full &context, int block_number, const hash256 &header_hash, + uint64_t nonce) noexcept; + + extern "C" EXPORT bool verify(const epoch_context &context, int block_number, const hash256 &header_hash, + const hash256 &mix_hash, uint64_t nonce, const hash256 &boundary) noexcept; + + // bool light_verify(const char* str_header_hash, + // const char* str_mix_hash, const char* str_nonce, const char* str_boundary, char* str_final) noexcept; + + search_result search_light(const epoch_context &context, int block_number, + const hash256 &header_hash, const hash256 &boundary, uint64_t start_nonce, + size_t iterations) noexcept; + + search_result search(const epoch_context_full &context, int block_number, + const hash256 &header_hash, const hash256 &boundary, uint64_t start_nonce, + size_t iterations) noexcept; + +} // namespace progpow diff --git a/src/Native/libfiropow/ethash/version.h b/src/Native/libfiropow/ethash/version.h new file mode 100644 index 000000000..f08900fc0 --- /dev/null +++ b/src/Native/libfiropow/ethash/version.h @@ -0,0 +1,18 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +/** The ethash library version. */ +#define ETHASH_VERSION "0.5.1-alpha.1" + +#ifdef __cplusplus +namespace ethash +{ +/// The ethash library version. +constexpr auto version = ETHASH_VERSION; + +} // namespace ethash +#endif diff --git a/src/Native/libfiropow/exports.cpp b/src/Native/libfiropow/exports.cpp new file mode 100644 index 000000000..2004b4f48 --- /dev/null +++ b/src/Native/libfiropow/exports.cpp @@ -0,0 +1,16 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/src/Native/libfiropow/keccak/CMakeLists.txt b/src/Native/libfiropow/keccak/CMakeLists.txt new file mode 100644 index 000000000..60f960f35 --- /dev/null +++ b/src/Native/libfiropow/keccak/CMakeLists.txt @@ -0,0 +1,26 @@ +# ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +# Copyright 2019 Pawel Bylica. +# Licensed under the Apache License, Version 2.0. + +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +add_library( + keccak + ${include_dir}/ethash/keccak.h + ${include_dir}/ethash/keccak.hpp + keccak.c + keccakf800.c + keccakf1600.c +) +set_property(TARGET keccak PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_include_directories(keccak PUBLIC $$) + +install( + TARGETS keccak + EXPORT ethashTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/Native/libfiropow/keccak/keccak.c b/src/Native/libfiropow/keccak/keccak.c new file mode 100644 index 000000000..3dfafdf2f --- /dev/null +++ b/src/Native/libfiropow/keccak/keccak.c @@ -0,0 +1,123 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#include "../ethash/keccak.h" + +#include "../support/attributes.h" +#include + +#if _WIN32 +/* On Windows assume little endian. */ +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN +#elif __APPLE__ +#include +#else +#include +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define to_le64(X) X +#else +#define to_le64(X) __builtin_bswap64(X) +#endif + + +/** Loads 64-bit integer from given memory location as little-endian number. */ +static INLINE ALWAYS_INLINE uint64_t load_le(const uint8_t* data) +{ + /* memcpy is the best way of expressing the intention. Every compiler will + optimize is to single load instruction if the target architecture + supports unaligned memory access (GCC and clang even in O0). + This is great trick because we are violating C/C++ memory alignment + restrictions with no performance penalty. */ + uint64_t word; + memcpy(&word, data, sizeof(word)); + return to_le64(word); +} + +static INLINE ALWAYS_INLINE void keccak( + uint64_t* out, size_t bits, const uint8_t* data, size_t size) +{ + static const size_t word_size = sizeof(uint64_t); + const size_t hash_size = bits / 8; + const size_t block_size = (1600 - bits * 2) / 8; + + size_t i; + uint64_t* state_iter; + uint64_t last_word = 0; + uint8_t* last_word_iter = (uint8_t*)&last_word; + + uint64_t state[25] = {0}; + + while (size >= block_size) + { + for (i = 0; i < (block_size / word_size); ++i) + { + state[i] ^= load_le(data); + data += word_size; + } + + ethash_keccakf1600(state); + + size -= block_size; + } + + state_iter = state; + + while (size >= word_size) + { + *state_iter ^= load_le(data); + ++state_iter; + data += word_size; + size -= word_size; + } + + while (size > 0) + { + *last_word_iter = *data; + ++last_word_iter; + ++data; + --size; + } + *last_word_iter = 0x01; + *state_iter ^= to_le64(last_word); + + state[(block_size / word_size) - 1] ^= 0x8000000000000000; + + ethash_keccakf1600(state); + + for (i = 0; i < (hash_size / word_size); ++i) + out[i] = to_le64(state[i]); +} + +union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) +{ + union ethash_hash256 hash; + keccak(hash.word64s, 256, data, size); + return hash; +} + +union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) +{ + union ethash_hash256 hash; + keccak(hash.word64s, 256, data, 32); + return hash; +} + +union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) +{ + union ethash_hash512 hash; + keccak(hash.word64s, 512, data, size); + return hash; +} + +union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) +{ + union ethash_hash512 hash; + keccak(hash.word64s, 512, data, 64); + return hash; +} diff --git a/src/Native/libfiropow/keccak/keccakf1600.c b/src/Native/libfiropow/keccak/keccakf1600.c new file mode 100644 index 000000000..e12b268d1 --- /dev/null +++ b/src/Native/libfiropow/keccak/keccakf1600.c @@ -0,0 +1,255 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#include + +static uint64_t rol(uint64_t x, unsigned s) +{ + return (x << s) | (x >> (64 - s)); +} + +static const uint64_t round_constants[24] = { + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808a, + 0x8000000080008000, + 0x000000000000808b, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008a, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000a, + 0x000000008000808b, + 0x800000000000008b, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800a, + 0x800000008000000a, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, +}; + +void ethash_keccakf1600(uint64_t state[25]) +{ + /* The implementation based on the "simple" implementation by Ronny Van Keer. */ + + int round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + uint64_t Ba, Be, Bi, Bo, Bu; + + uint64_t Da, De, Di, Do, Du; + + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < 24; round += 2) + { + /* Round (round + 0): Axx -> Exx */ + + Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + Be = Abe ^ Age ^ Ake ^ Ame ^ Ase; + Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Aba ^ Da; + Be = rol(Age ^ De, 44); + Bi = rol(Aki ^ Di, 43); + Bo = rol(Amo ^ Do, 21); + Bu = rol(Asu ^ Du, 14); + Eba = Ba ^ (~Be & Bi) ^ round_constants[round]; + Ebe = Be ^ (~Bi & Bo); + Ebi = Bi ^ (~Bo & Bu); + Ebo = Bo ^ (~Bu & Ba); + Ebu = Bu ^ (~Ba & Be); + + Ba = rol(Abo ^ Do, 28); + Be = rol(Agu ^ Du, 20); + Bi = rol(Aka ^ Da, 3); + Bo = rol(Ame ^ De, 45); + Bu = rol(Asi ^ Di, 61); + Ega = Ba ^ (~Be & Bi); + Ege = Be ^ (~Bi & Bo); + Egi = Bi ^ (~Bo & Bu); + Ego = Bo ^ (~Bu & Ba); + Egu = Bu ^ (~Ba & Be); + + Ba = rol(Abe ^ De, 1); + Be = rol(Agi ^ Di, 6); + Bi = rol(Ako ^ Do, 25); + Bo = rol(Amu ^ Du, 8); + Bu = rol(Asa ^ Da, 18); + Eka = Ba ^ (~Be & Bi); + Eke = Be ^ (~Bi & Bo); + Eki = Bi ^ (~Bo & Bu); + Eko = Bo ^ (~Bu & Ba); + Eku = Bu ^ (~Ba & Be); + + Ba = rol(Abu ^ Du, 27); + Be = rol(Aga ^ Da, 36); + Bi = rol(Ake ^ De, 10); + Bo = rol(Ami ^ Di, 15); + Bu = rol(Aso ^ Do, 56); + Ema = Ba ^ (~Be & Bi); + Eme = Be ^ (~Bi & Bo); + Emi = Bi ^ (~Bo & Bu); + Emo = Bo ^ (~Bu & Ba); + Emu = Bu ^ (~Ba & Be); + + Ba = rol(Abi ^ Di, 62); + Be = rol(Ago ^ Do, 55); + Bi = rol(Aku ^ Du, 39); + Bo = rol(Ama ^ Da, 41); + Bu = rol(Ase ^ De, 2); + Esa = Ba ^ (~Be & Bi); + Ese = Be ^ (~Bi & Bo); + Esi = Bi ^ (~Bo & Bu); + Eso = Bo ^ (~Bu & Ba); + Esu = Bu ^ (~Ba & Be); + + + /* Round (round + 1): Exx -> Axx */ + + Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Eba ^ Da; + Be = rol(Ege ^ De, 44); + Bi = rol(Eki ^ Di, 43); + Bo = rol(Emo ^ Do, 21); + Bu = rol(Esu ^ Du, 14); + Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1]; + Abe = Be ^ (~Bi & Bo); + Abi = Bi ^ (~Bo & Bu); + Abo = Bo ^ (~Bu & Ba); + Abu = Bu ^ (~Ba & Be); + + Ba = rol(Ebo ^ Do, 28); + Be = rol(Egu ^ Du, 20); + Bi = rol(Eka ^ Da, 3); + Bo = rol(Eme ^ De, 45); + Bu = rol(Esi ^ Di, 61); + Aga = Ba ^ (~Be & Bi); + Age = Be ^ (~Bi & Bo); + Agi = Bi ^ (~Bo & Bu); + Ago = Bo ^ (~Bu & Ba); + Agu = Bu ^ (~Ba & Be); + + Ba = rol(Ebe ^ De, 1); + Be = rol(Egi ^ Di, 6); + Bi = rol(Eko ^ Do, 25); + Bo = rol(Emu ^ Du, 8); + Bu = rol(Esa ^ Da, 18); + Aka = Ba ^ (~Be & Bi); + Ake = Be ^ (~Bi & Bo); + Aki = Bi ^ (~Bo & Bu); + Ako = Bo ^ (~Bu & Ba); + Aku = Bu ^ (~Ba & Be); + + Ba = rol(Ebu ^ Du, 27); + Be = rol(Ega ^ Da, 36); + Bi = rol(Eke ^ De, 10); + Bo = rol(Emi ^ Di, 15); + Bu = rol(Eso ^ Do, 56); + Ama = Ba ^ (~Be & Bi); + Ame = Be ^ (~Bi & Bo); + Ami = Bi ^ (~Bo & Bu); + Amo = Bo ^ (~Bu & Ba); + Amu = Bu ^ (~Ba & Be); + + Ba = rol(Ebi ^ Di, 62); + Be = rol(Ego ^ Do, 55); + Bi = rol(Eku ^ Du, 39); + Bo = rol(Ema ^ Da, 41); + Bu = rol(Ese ^ De, 2); + Asa = Ba ^ (~Be & Bi); + Ase = Be ^ (~Bi & Bo); + Asi = Bi ^ (~Bo & Bu); + Aso = Bo ^ (~Bu & Ba); + Asu = Bu ^ (~Ba & Be); + } + + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} diff --git a/src/Native/libfiropow/keccak/keccakf800.c b/src/Native/libfiropow/keccak/keccakf800.c new file mode 100644 index 000000000..5b9a18025 --- /dev/null +++ b/src/Native/libfiropow/keccak/keccakf800.c @@ -0,0 +1,253 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#include + +static uint32_t rol(uint32_t x, unsigned s) +{ + return (x << s) | (x >> (32 - s)); +} + +static const uint32_t round_constants[22] = { + 0x00000001, + 0x00008082, + 0x0000808A, + 0x80008000, + 0x0000808B, + 0x80000001, + 0x80008081, + 0x00008009, + 0x0000008A, + 0x00000088, + 0x80008009, + 0x8000000A, + 0x8000808B, + 0x0000008B, + 0x00008089, + 0x00008003, + 0x00008002, + 0x00000080, + 0x0000800A, + 0x8000000A, + 0x80008081, + 0x00008080, +}; + +void ethash_keccakf800(uint32_t state[25]) +{ + /* The implementation directly translated from ethash_keccakf1600. */ + + int round; + + uint32_t Aba, Abe, Abi, Abo, Abu; + uint32_t Aga, Age, Agi, Ago, Agu; + uint32_t Aka, Ake, Aki, Ako, Aku; + uint32_t Ama, Ame, Ami, Amo, Amu; + uint32_t Asa, Ase, Asi, Aso, Asu; + + uint32_t Eba, Ebe, Ebi, Ebo, Ebu; + uint32_t Ega, Ege, Egi, Ego, Egu; + uint32_t Eka, Eke, Eki, Eko, Eku; + uint32_t Ema, Eme, Emi, Emo, Emu; + uint32_t Esa, Ese, Esi, Eso, Esu; + + uint32_t Ba, Be, Bi, Bo, Bu; + + uint32_t Da, De, Di, Do, Du; + + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < 22; round += 2) + { + /* Round (round + 0): Axx -> Exx */ + + Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + Be = Abe ^ Age ^ Ake ^ Ame ^ Ase; + Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Aba ^ Da; + Be = rol(Age ^ De, 12); + Bi = rol(Aki ^ Di, 11); + Bo = rol(Amo ^ Do, 21); + Bu = rol(Asu ^ Du, 14); + Eba = Ba ^ (~Be & Bi) ^ round_constants[round]; + Ebe = Be ^ (~Bi & Bo); + Ebi = Bi ^ (~Bo & Bu); + Ebo = Bo ^ (~Bu & Ba); + Ebu = Bu ^ (~Ba & Be); + + Ba = rol(Abo ^ Do, 28); + Be = rol(Agu ^ Du, 20); + Bi = rol(Aka ^ Da, 3); + Bo = rol(Ame ^ De, 13); + Bu = rol(Asi ^ Di, 29); + Ega = Ba ^ (~Be & Bi); + Ege = Be ^ (~Bi & Bo); + Egi = Bi ^ (~Bo & Bu); + Ego = Bo ^ (~Bu & Ba); + Egu = Bu ^ (~Ba & Be); + + Ba = rol(Abe ^ De, 1); + Be = rol(Agi ^ Di, 6); + Bi = rol(Ako ^ Do, 25); + Bo = rol(Amu ^ Du, 8); + Bu = rol(Asa ^ Da, 18); + Eka = Ba ^ (~Be & Bi); + Eke = Be ^ (~Bi & Bo); + Eki = Bi ^ (~Bo & Bu); + Eko = Bo ^ (~Bu & Ba); + Eku = Bu ^ (~Ba & Be); + + Ba = rol(Abu ^ Du, 27); + Be = rol(Aga ^ Da, 4); + Bi = rol(Ake ^ De, 10); + Bo = rol(Ami ^ Di, 15); + Bu = rol(Aso ^ Do, 24); + Ema = Ba ^ (~Be & Bi); + Eme = Be ^ (~Bi & Bo); + Emi = Bi ^ (~Bo & Bu); + Emo = Bo ^ (~Bu & Ba); + Emu = Bu ^ (~Ba & Be); + + Ba = rol(Abi ^ Di, 30); + Be = rol(Ago ^ Do, 23); + Bi = rol(Aku ^ Du, 7); + Bo = rol(Ama ^ Da, 9); + Bu = rol(Ase ^ De, 2); + Esa = Ba ^ (~Be & Bi); + Ese = Be ^ (~Bi & Bo); + Esi = Bi ^ (~Bo & Bu); + Eso = Bo ^ (~Bu & Ba); + Esu = Bu ^ (~Ba & Be); + + + /* Round (round + 1): Exx -> Axx */ + + Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Eba ^ Da; + Be = rol(Ege ^ De, 12); + Bi = rol(Eki ^ Di, 11); + Bo = rol(Emo ^ Do, 21); + Bu = rol(Esu ^ Du, 14); + Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1]; + Abe = Be ^ (~Bi & Bo); + Abi = Bi ^ (~Bo & Bu); + Abo = Bo ^ (~Bu & Ba); + Abu = Bu ^ (~Ba & Be); + + Ba = rol(Ebo ^ Do, 28); + Be = rol(Egu ^ Du, 20); + Bi = rol(Eka ^ Da, 3); + Bo = rol(Eme ^ De, 13); + Bu = rol(Esi ^ Di, 29); + Aga = Ba ^ (~Be & Bi); + Age = Be ^ (~Bi & Bo); + Agi = Bi ^ (~Bo & Bu); + Ago = Bo ^ (~Bu & Ba); + Agu = Bu ^ (~Ba & Be); + + Ba = rol(Ebe ^ De, 1); + Be = rol(Egi ^ Di, 6); + Bi = rol(Eko ^ Do, 25); + Bo = rol(Emu ^ Du, 8); + Bu = rol(Esa ^ Da, 18); + Aka = Ba ^ (~Be & Bi); + Ake = Be ^ (~Bi & Bo); + Aki = Bi ^ (~Bo & Bu); + Ako = Bo ^ (~Bu & Ba); + Aku = Bu ^ (~Ba & Be); + + Ba = rol(Ebu ^ Du, 27); + Be = rol(Ega ^ Da, 4); + Bi = rol(Eke ^ De, 10); + Bo = rol(Emi ^ Di, 15); + Bu = rol(Eso ^ Do, 24); + Ama = Ba ^ (~Be & Bi); + Ame = Be ^ (~Bi & Bo); + Ami = Bi ^ (~Bo & Bu); + Amo = Bo ^ (~Bu & Ba); + Amu = Bu ^ (~Ba & Be); + + Ba = rol(Ebi ^ Di, 30); + Be = rol(Ego ^ Do, 23); + Bi = rol(Eku ^ Du, 7); + Bo = rol(Ema ^ Da, 9); + Bu = rol(Ese ^ De, 2); + Asa = Ba ^ (~Be & Bi); + Ase = Be ^ (~Bi & Bo); + Asi = Bi ^ (~Bo & Bu); + Aso = Bo ^ (~Bu & Ba); + Asu = Bu ^ (~Ba & Be); + } + + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} diff --git a/src/Native/libfiropow/libfiropow.sln b/src/Native/libfiropow/libfiropow.sln new file mode 100644 index 000000000..70f294314 --- /dev/null +++ b/src/Native/libfiropow/libfiropow.sln @@ -0,0 +1,31 @@ + +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", "libfiropow.vcxproj", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + 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 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libfiropow/libfiropow.vcxproj b/src/Native/libfiropow/libfiropow.vcxproj new file mode 100644 index 000000000..225c4ed87 --- /dev/null +++ b/src/Native/libfiropow/libfiropow.vcxproj @@ -0,0 +1,206 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libfiropow + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libfiropow/stdafx.cpp b/src/Native/libfiropow/stdafx.cpp new file mode 100644 index 000000000..bd27597c6 --- /dev/null +++ b/src/Native/libfiropow/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// $safeprojectname$.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/src/Native/libfiropow/stdafx.h b/src/Native/libfiropow/stdafx.h new file mode 100644 index 000000000..f3a07375c --- /dev/null +++ b/src/Native/libfiropow/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + + + +// TODO: reference additional headers your program requires here diff --git a/src/Native/libfiropow/support/attributes.h b/src/Native/libfiropow/support/attributes.h new file mode 100644 index 000000000..83be231f0 --- /dev/null +++ b/src/Native/libfiropow/support/attributes.h @@ -0,0 +1,33 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +/** inline */ +#if _MSC_VER || __STDC_VERSION__ +#define INLINE inline +#else +#define INLINE +#endif + +/** [[always_inline]] */ +#if _MSC_VER +#define ALWAYS_INLINE __forceinline +#elif defined(__has_attribute) && __STDC_VERSION__ +#if __has_attribute(always_inline) +#define ALWAYS_INLINE __attribute__((always_inline)) +#endif +#endif +#if !defined(ALWAYS_INLINE) +#define ALWAYS_INLINE +#endif + +/** [[no_sanitize()]] */ +#if __clang__ +#define NO_SANITIZE(sanitizer) \ + __attribute__((no_sanitize(sanitizer))) +#else +#define NO_SANITIZE(sanitizer) +#endif diff --git a/src/Native/libfiropow/targetver.h b/src/Native/libfiropow/targetver.h new file mode 100644 index 000000000..87c0086de --- /dev/null +++ b/src/Native/libfiropow/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/src/Native/libkawpow/ethash/ethash.cpp b/src/Native/libkawpow/ethash/ethash.cpp index 436ded06b..9f3236535 100644 --- a/src/Native/libkawpow/ethash/ethash.cpp +++ b/src/Native/libkawpow/ethash/ethash.cpp @@ -20,425 +20,424 @@ namespace ethash { -// Internal constants: -constexpr static int light_cache_init_size = 1 << 24; -constexpr static int light_cache_growth = 1 << 17; -constexpr static int light_cache_rounds = 3; -constexpr static int full_dataset_init_size = 1 << 30; -constexpr static int full_dataset_growth = 1 << 23; -constexpr static int full_dataset_item_parents = 512; - -// Verify constants: -static_assert(sizeof(hash512) == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); -static_assert(sizeof(hash1024) == ETHASH_FULL_DATASET_ITEM_SIZE, ""); -static_assert(light_cache_item_size == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); -static_assert(full_dataset_item_size == ETHASH_FULL_DATASET_ITEM_SIZE, ""); - - -namespace -{ -using ::fnv1; + // Internal constants: + constexpr static int light_cache_init_size = 1 << 24; + constexpr static int light_cache_growth = 1 << 17; + constexpr static int light_cache_rounds = 3; + constexpr static int full_dataset_init_size = 1 << 30; + constexpr static int full_dataset_growth = 1 << 23; + constexpr static int full_dataset_item_parents = 512; + + // Verify constants: + static_assert(sizeof(hash512) == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); + static_assert(sizeof(hash1024) == ETHASH_FULL_DATASET_ITEM_SIZE, ""); + static_assert(light_cache_item_size == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); + static_assert(full_dataset_item_size == ETHASH_FULL_DATASET_ITEM_SIZE, ""); + + namespace + { + using ::fnv1; -inline hash512 fnv1(const hash512& u, const hash512& v) noexcept -{ - hash512 r; - for (size_t i = 0; i < sizeof(r) / sizeof(r.word32s[0]); ++i) - r.word32s[i] = fnv1(u.word32s[i], v.word32s[i]); - return r; -} + inline hash512 fnv1(const hash512 &u, const hash512 &v) noexcept + { + hash512 r; + for (size_t i = 0; i < sizeof(r) / sizeof(r.word32s[0]); ++i) + r.word32s[i] = fnv1(u.word32s[i], v.word32s[i]); + return r; + } -inline hash512 bitwise_xor(const hash512& x, const hash512& y) noexcept -{ - hash512 z; - for (size_t i = 0; i < sizeof(z) / sizeof(z.word64s[0]); ++i) - z.word64s[i] = x.word64s[i] ^ y.word64s[i]; - return z; -} -} // namespace - -int find_epoch_number(const hash256& seed) noexcept -{ - static constexpr int num_tries = 30000; // Divisible by 16. + inline hash512 bitwise_xor(const hash512 &x, const hash512 &y) noexcept + { + hash512 z; + for (size_t i = 0; i < sizeof(z) / sizeof(z.word64s[0]); ++i) + z.word64s[i] = x.word64s[i] ^ y.word64s[i]; + return z; + } + } // namespace - // Thread-local cache of the last search. - static thread_local int cached_epoch_number = 0; - static thread_local hash256 cached_seed = {}; + int find_epoch_number(const hash256 &seed) noexcept + { + static constexpr int num_tries = 30000; // Divisible by 16. - // Load from memory once (memory will be clobbered by keccak256()). - const uint32_t seed_part = seed.word32s[0]; - const int e = cached_epoch_number; - hash256 s = cached_seed; + // Thread-local cache of the last search. + static thread_local int cached_epoch_number = 0; + static thread_local hash256 cached_seed = {}; - if (s.word32s[0] == seed_part) - return e; + // Load from memory once (memory will be clobbered by keccak256()). + const uint32_t seed_part = seed.word32s[0]; + const int e = cached_epoch_number; + hash256 s = cached_seed; - // Try the next seed, will match for sequential epoch access. - s = keccak256(s); - if (s.word32s[0] == seed_part) - { - cached_seed = s; - cached_epoch_number = e + 1; - return e + 1; - } + if (s.word32s[0] == seed_part) + return e; - // Search for matching seed starting from epoch 0. - s = {}; - for (int i = 0; i < num_tries; ++i) - { + // Try the next seed, will match for sequential epoch access. + s = keccak256(s); if (s.word32s[0] == seed_part) { cached_seed = s; - cached_epoch_number = i; - return i; + cached_epoch_number = e + 1; + return e + 1; } - s = keccak256(s); - } - - return -1; -} + // Search for matching seed starting from epoch 0. + s = {}; + for (int i = 0; i < num_tries; ++i) + { + if (s.word32s[0] == seed_part) + { + cached_seed = s; + cached_epoch_number = i; + return i; + } + + s = keccak256(s); + } -namespace generic -{ -void build_light_cache( - hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256& seed) noexcept -{ - hash512 item = hash_fn(seed.bytes, sizeof(seed)); - cache[0] = item; - for (int i = 1; i < num_items; ++i) - { - item = hash_fn(item.bytes, sizeof(item)); - cache[i] = item; + return -1; } - for (int q = 0; q < light_cache_rounds; ++q) + namespace generic { - for (int i = 0; i < num_items; ++i) + void build_light_cache( + hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256 &seed) noexcept { - const uint32_t index_limit = static_cast(num_items); - - // Fist index: 4 first bytes of the item as little-endian integer. - const uint32_t t = le::uint32(cache[i].word32s[0]); - const uint32_t v = t % index_limit; - - // Second index. - const uint32_t w = static_cast(num_items + (i - 1)) % index_limit; + hash512 item = hash_fn(seed.bytes, sizeof(seed)); + cache[0] = item; + for (int i = 1; i < num_items; ++i) + { + item = hash_fn(item.bytes, sizeof(item)); + cache[i] = item; + } + + for (int q = 0; q < light_cache_rounds; ++q) + { + for (int i = 0; i < num_items; ++i) + { + const uint32_t index_limit = static_cast(num_items); + + // Fist index: 4 first bytes of the item as little-endian integer. + const uint32_t t = le::uint32(cache[i].word32s[0]); + const uint32_t v = t % index_limit; + + // Second index. + const uint32_t w = static_cast(num_items + (i - 1)) % index_limit; + + const hash512 x = bitwise_xor(cache[v], cache[w]); + cache[i] = hash_fn(x.bytes, sizeof(x)); + } + } + } - const hash512 x = bitwise_xor(cache[v], cache[w]); - cache[i] = hash_fn(x.bytes, sizeof(x)); + epoch_context_full *create_epoch_context( + build_light_cache_fn build_fn, int epoch_number, bool full) noexcept + { + static_assert(sizeof(epoch_context_full) < sizeof(hash512), "epoch_context too big"); + static constexpr size_t context_alloc_size = sizeof(hash512); + + const int light_cache_num_items = calculate_light_cache_num_items(epoch_number); + const int full_dataset_num_items = calculate_full_dataset_num_items(epoch_number); + const size_t light_cache_size = get_light_cache_size(light_cache_num_items); + const size_t full_dataset_size = + full ? static_cast(full_dataset_num_items) * sizeof(hash1024) : progpow::l1_cache_size; + + const size_t alloc_size = context_alloc_size + light_cache_size + full_dataset_size; + + char *const alloc_data = static_cast(std::calloc(1, alloc_size)); + if (!alloc_data) + return nullptr; // Signal out-of-memory by returning null pointer. + + hash512 *const light_cache = reinterpret_cast(alloc_data + context_alloc_size); + const hash256 epoch_seed = calculate_epoch_seed(epoch_number); + build_fn(light_cache, light_cache_num_items, epoch_seed); + + uint32_t *const l1_cache = + reinterpret_cast(alloc_data + context_alloc_size + light_cache_size); + + hash1024 *full_dataset = full ? reinterpret_cast(l1_cache) : nullptr; + + epoch_context_full *const context = new (alloc_data) epoch_context_full{ + epoch_number, + light_cache_num_items, + light_cache, + l1_cache, + full_dataset_num_items, + full_dataset, + }; + + auto *full_dataset_2048 = reinterpret_cast(l1_cache); + for (uint32_t i = 0; i < progpow::l1_cache_size / sizeof(full_dataset_2048[0]); ++i) + full_dataset_2048[i] = calculate_dataset_item_2048(*context, i); + return context; } + } // namespace generic + + void build_light_cache(hash512 cache[], int num_items, const hash256 &seed) noexcept + { + return generic::build_light_cache(keccak512, cache, num_items, seed); } -} -epoch_context_full* create_epoch_context( - build_light_cache_fn build_fn, int epoch_number, bool full) noexcept -{ - static_assert(sizeof(epoch_context_full) < sizeof(hash512), "epoch_context too big"); - static constexpr size_t context_alloc_size = sizeof(hash512); - - const int light_cache_num_items = calculate_light_cache_num_items(epoch_number); - const int full_dataset_num_items = calculate_full_dataset_num_items(epoch_number); - const size_t light_cache_size = get_light_cache_size(light_cache_num_items); - const size_t full_dataset_size = - full ? static_cast(full_dataset_num_items) * sizeof(hash1024) : - progpow::l1_cache_size; - - const size_t alloc_size = context_alloc_size + light_cache_size + full_dataset_size; - - char* const alloc_data = static_cast(std::calloc(1, alloc_size)); - if (!alloc_data) - return nullptr; // Signal out-of-memory by returning null pointer. - - hash512* const light_cache = reinterpret_cast(alloc_data + context_alloc_size); - const hash256 epoch_seed = calculate_epoch_seed(epoch_number); - build_fn(light_cache, light_cache_num_items, epoch_seed); - - uint32_t* const l1_cache = - reinterpret_cast(alloc_data + context_alloc_size + light_cache_size); - - hash1024* full_dataset = full ? reinterpret_cast(l1_cache) : nullptr; - - epoch_context_full* const context = new (alloc_data) epoch_context_full{ - epoch_number, - light_cache_num_items, - light_cache, - l1_cache, - full_dataset_num_items, - full_dataset, - }; + struct item_state + { + const hash512 *const cache; + const int64_t num_cache_items; + const uint32_t seed; - auto* full_dataset_2048 = reinterpret_cast(l1_cache); - for (uint32_t i = 0; i < progpow::l1_cache_size / sizeof(full_dataset_2048[0]); ++i) - full_dataset_2048[i] = calculate_dataset_item_2048(*context, i); - return context; -} -} // namespace generic + hash512 mix; -void build_light_cache(hash512 cache[], int num_items, const hash256& seed) noexcept -{ - return generic::build_light_cache(keccak512, cache, num_items, seed); -} + ALWAYS_INLINE item_state(const epoch_context &context, int64_t index) noexcept + : cache{context.light_cache}, + num_cache_items{context.light_cache_num_items}, + seed{static_cast(index)} + { + mix = cache[index % num_cache_items]; + mix.word32s[0] ^= le::uint32(seed); + mix = le::uint32s(keccak512(mix)); + } -struct item_state -{ - const hash512* const cache; - const int64_t num_cache_items; - const uint32_t seed; + ALWAYS_INLINE void update(uint32_t round) noexcept + { + static constexpr size_t num_words = sizeof(mix) / sizeof(uint32_t); + const uint32_t t = fnv1(seed ^ round, mix.word32s[round % num_words]); + const int64_t parent_index = t % num_cache_items; + mix = fnv1(mix, le::uint32s(cache[parent_index])); + } - hash512 mix; + ALWAYS_INLINE hash512 final() noexcept { return keccak512(le::uint32s(mix)); } + }; - ALWAYS_INLINE item_state(const epoch_context& context, int64_t index) noexcept - : cache{context.light_cache}, - num_cache_items{context.light_cache_num_items}, - seed{static_cast(index)} + hash512 calculate_dataset_item_512(const epoch_context &context, int64_t index) noexcept { - mix = cache[index % num_cache_items]; - mix.word32s[0] ^= le::uint32(seed); - mix = le::uint32s(keccak512(mix)); + item_state item0{context, index}; + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + item0.update(j); + return item0.final(); } - ALWAYS_INLINE void update(uint32_t round) noexcept + /// Calculates a full dataset item + /// + /// This consist of two 512-bit items produced by calculate_dataset_item_partial(). + /// Here the computation is done interleaved for better performance. + hash1024 calculate_dataset_item_1024(const epoch_context &context, uint32_t index) noexcept { - static constexpr size_t num_words = sizeof(mix) / sizeof(uint32_t); - const uint32_t t = fnv1(seed ^ round, mix.word32s[round % num_words]); - const int64_t parent_index = t % num_cache_items; - mix = fnv1(mix, le::uint32s(cache[parent_index])); - } + item_state item0{context, int64_t(index) * 2}; + item_state item1{context, int64_t(index) * 2 + 1}; - ALWAYS_INLINE hash512 final() noexcept { return keccak512(le::uint32s(mix)); } -}; - -hash512 calculate_dataset_item_512(const epoch_context& context, int64_t index) noexcept -{ - item_state item0{context, index}; - for (uint32_t j = 0; j < full_dataset_item_parents; ++j) - item0.update(j); - return item0.final(); -} - -/// Calculates a full dataset item -/// -/// This consist of two 512-bit items produced by calculate_dataset_item_partial(). -/// Here the computation is done interleaved for better performance. -hash1024 calculate_dataset_item_1024(const epoch_context& context, uint32_t index) noexcept -{ - item_state item0{context, int64_t(index) * 2}; - item_state item1{context, int64_t(index) * 2 + 1}; + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + { + item0.update(j); + item1.update(j); + } - for (uint32_t j = 0; j < full_dataset_item_parents; ++j) - { - item0.update(j); - item1.update(j); + return hash1024{{item0.final(), item1.final()}}; } - return hash1024{{item0.final(), item1.final()}}; -} + hash2048 calculate_dataset_item_2048(const epoch_context &context, uint32_t index) noexcept + { + item_state item0{context, int64_t(index) * 4}; + item_state item1{context, int64_t(index) * 4 + 1}; + item_state item2{context, int64_t(index) * 4 + 2}; + item_state item3{context, int64_t(index) * 4 + 3}; -hash2048 calculate_dataset_item_2048(const epoch_context& context, uint32_t index) noexcept -{ - item_state item0{context, int64_t(index) * 4}; - item_state item1{context, int64_t(index) * 4 + 1}; - item_state item2{context, int64_t(index) * 4 + 2}; - item_state item3{context, int64_t(index) * 4 + 3}; + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + { + item0.update(j); + item1.update(j); + item2.update(j); + item3.update(j); + } - for (uint32_t j = 0; j < full_dataset_item_parents; ++j) - { - item0.update(j); - item1.update(j); - item2.update(j); - item3.update(j); + return hash2048{{item0.final(), item1.final(), item2.final(), item3.final()}}; } - return hash2048{{item0.final(), item1.final(), item2.final(), item3.final()}}; -} - -namespace -{ -using lookup_fn = hash1024 (*)(const epoch_context&, uint32_t); + namespace + { + using lookup_fn = hash1024 (*)(const epoch_context &, uint32_t); -inline hash512 hash_seed(const hash256& header_hash, uint64_t nonce) noexcept -{ - nonce = le::uint64(nonce); - uint8_t init_data[sizeof(header_hash) + sizeof(nonce)]; - std::memcpy(&init_data[0], &header_hash, sizeof(header_hash)); - std::memcpy(&init_data[sizeof(header_hash)], &nonce, sizeof(nonce)); + inline hash512 hash_seed(const hash256 &header_hash, uint64_t nonce) noexcept + { + nonce = le::uint64(nonce); + uint8_t init_data[sizeof(header_hash) + sizeof(nonce)]; + std::memcpy(&init_data[0], &header_hash, sizeof(header_hash)); + std::memcpy(&init_data[sizeof(header_hash)], &nonce, sizeof(nonce)); - return keccak512(init_data, sizeof(init_data)); -} + return keccak512(init_data, sizeof(init_data)); + } -inline hash256 hash_final(const hash512& seed, const hash256& mix_hash) -{ - uint8_t final_data[sizeof(seed) + sizeof(mix_hash)]; - std::memcpy(&final_data[0], seed.bytes, sizeof(seed)); - std::memcpy(&final_data[sizeof(seed)], mix_hash.bytes, sizeof(mix_hash)); - return keccak256(final_data, sizeof(final_data)); -} - -inline hash256 hash_kernel( - const epoch_context& context, const hash512& seed, lookup_fn lookup) noexcept -{ - static constexpr size_t num_words = sizeof(hash1024) / sizeof(uint32_t); - const uint32_t index_limit = static_cast(context.full_dataset_num_items); - const uint32_t seed_init = le::uint32(seed.word32s[0]); + inline hash256 hash_final(const hash512 &seed, const hash256 &mix_hash) + { + uint8_t final_data[sizeof(seed) + sizeof(mix_hash)]; + std::memcpy(&final_data[0], seed.bytes, sizeof(seed)); + std::memcpy(&final_data[sizeof(seed)], mix_hash.bytes, sizeof(mix_hash)); + return keccak256(final_data, sizeof(final_data)); + } - hash1024 mix{{le::uint32s(seed), le::uint32s(seed)}}; + inline hash256 hash_kernel( + const epoch_context &context, const hash512 &seed, lookup_fn lookup) noexcept + { + static constexpr size_t num_words = sizeof(hash1024) / sizeof(uint32_t); + const uint32_t index_limit = static_cast(context.full_dataset_num_items); + const uint32_t seed_init = le::uint32(seed.word32s[0]); + + hash1024 mix{{le::uint32s(seed), le::uint32s(seed)}}; + + for (uint32_t i = 0; i < num_dataset_accesses; ++i) + { + const uint32_t p = fnv1(i ^ seed_init, mix.word32s[i % num_words]) % index_limit; + const hash1024 newdata = le::uint32s(lookup(context, p)); + + for (size_t j = 0; j < num_words; ++j) + mix.word32s[j] = fnv1(mix.word32s[j], newdata.word32s[j]); + } + + hash256 mix_hash; + for (size_t i = 0; i < num_words; i += 4) + { + const uint32_t h1 = fnv1(mix.word32s[i], mix.word32s[i + 1]); + const uint32_t h2 = fnv1(h1, mix.word32s[i + 2]); + const uint32_t h3 = fnv1(h2, mix.word32s[i + 3]); + mix_hash.word32s[i / 4] = h3; + } + + return le::uint32s(mix_hash); + } + } // namespace - for (uint32_t i = 0; i < num_dataset_accesses; ++i) + result hash(const epoch_context_full &context, const hash256 &header_hash, uint64_t nonce) noexcept { - const uint32_t p = fnv1(i ^ seed_init, mix.word32s[i % num_words]) % index_limit; - const hash1024 newdata = le::uint32s(lookup(context, p)); - - for (size_t j = 0; j < num_words; ++j) - mix.word32s[j] = fnv1(mix.word32s[j], newdata.word32s[j]); + static const auto lazy_lookup = [](const epoch_context &ctx, uint32_t index) noexcept + { + auto full_dataset = static_cast(ctx).full_dataset; + hash1024 &item = full_dataset[index]; + if (item.word64s[0] == 0) + { + // TODO: Copy elision here makes it thread-safe? + item = calculate_dataset_item_1024(ctx, index); + } + + return item; + }; + + const hash512 seed = hash_seed(header_hash, nonce); + const hash256 mix_hash = hash_kernel(context, seed, lazy_lookup); + return {hash_final(seed, mix_hash), mix_hash}; } - hash256 mix_hash; - for (size_t i = 0; i < num_words; i += 4) + search_result search_light(const epoch_context &context, const hash256 &header_hash, + const hash256 &boundary, uint64_t start_nonce, size_t iterations) noexcept { - const uint32_t h1 = fnv1(mix.word32s[i], mix.word32s[i + 1]); - const uint32_t h2 = fnv1(h1, mix.word32s[i + 2]); - const uint32_t h3 = fnv1(h2, mix.word32s[i + 3]); - mix_hash.word32s[i / 4] = h3; + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; } - return le::uint32s(mix_hash); -} -} // namespace - -result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept -{ - static const auto lazy_lookup = [](const epoch_context& ctx, uint32_t index) noexcept { - auto full_dataset = static_cast(ctx).full_dataset; - hash1024& item = full_dataset[index]; - if (item.word64s[0] == 0) + search_result search(const epoch_context_full &context, const hash256 &header_hash, + const hash256 &boundary, uint64_t start_nonce, size_t iterations) noexcept + { + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) { - // TODO: Copy elision here makes it thread-safe? - item = calculate_dataset_item_1024(ctx, index); + result r = hash(context, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; } + return {}; + } +} // namespace ethash - return item; - }; - - const hash512 seed = hash_seed(header_hash, nonce); - const hash256 mix_hash = hash_kernel(context, seed, lazy_lookup); - return {hash_final(seed, mix_hash), mix_hash}; -} +using namespace ethash; -search_result search_light(const epoch_context& context, const hash256& header_hash, - const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept +extern "C" { - const uint64_t end_nonce = start_nonce + iterations; - for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + + ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) noexcept { - result r = hash(context, header_hash, nonce); - if (is_less_or_equal(r.final_hash, boundary)) - return {r, nonce}; + ethash_hash256 epoch_seed = {}; + for (int i = 0; i < epoch_number; ++i) + epoch_seed = ethash_keccak256_32(epoch_seed.bytes); + return epoch_seed; } - return {}; -} -search_result search(const epoch_context_full& context, const hash256& header_hash, - const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept -{ - const uint64_t end_nonce = start_nonce + iterations; - for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + int ethash_calculate_light_cache_num_items(int epoch_number) noexcept { - result r = hash(context, header_hash, nonce); - if (is_less_or_equal(r.final_hash, boundary)) - return {r, nonce}; + static constexpr int item_size = sizeof(hash512); + static constexpr int num_items_init = light_cache_init_size / item_size; + static constexpr int num_items_growth = light_cache_growth / item_size; + static_assert( + light_cache_init_size % item_size == 0, "light_cache_init_size not multiple of item size"); + static_assert( + light_cache_growth % item_size == 0, "light_cache_growth not multiple of item size"); + + int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; + int num_items = ethash_find_largest_prime(num_items_upper_bound); + return num_items; } - return {}; -} -} // namespace ethash - -using namespace ethash; - -extern "C" { -ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) noexcept -{ - ethash_hash256 epoch_seed = {}; - for (int i = 0; i < epoch_number; ++i) - epoch_seed = ethash_keccak256_32(epoch_seed.bytes); - return epoch_seed; -} - -int ethash_calculate_light_cache_num_items(int epoch_number) noexcept -{ - static constexpr int item_size = sizeof(hash512); - static constexpr int num_items_init = light_cache_init_size / item_size; - static constexpr int num_items_growth = light_cache_growth / item_size; - static_assert( - light_cache_init_size % item_size == 0, "light_cache_init_size not multiple of item size"); - static_assert( - light_cache_growth % item_size == 0, "light_cache_growth not multiple of item size"); - - int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; - int num_items = ethash_find_largest_prime(num_items_upper_bound); - return num_items; -} - -int ethash_calculate_full_dataset_num_items(int epoch_number) noexcept -{ - static constexpr int item_size = sizeof(hash1024); - static constexpr int num_items_init = full_dataset_init_size / item_size; - static constexpr int num_items_growth = full_dataset_growth / item_size; - static_assert(full_dataset_init_size % item_size == 0, - "full_dataset_init_size not multiple of item size"); - static_assert( - full_dataset_growth % item_size == 0, "full_dataset_growth not multiple of item size"); - - int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; - int num_items = ethash_find_largest_prime(num_items_upper_bound); - return num_items; -} - -epoch_context* ethash_create_epoch_context(int epoch_number) noexcept -{ - return generic::create_epoch_context(build_light_cache, epoch_number, false); -} + int ethash_calculate_full_dataset_num_items(int epoch_number) noexcept + { + static constexpr int item_size = sizeof(hash1024); + static constexpr int num_items_init = full_dataset_init_size / item_size; + static constexpr int num_items_growth = full_dataset_growth / item_size; + static_assert(full_dataset_init_size % item_size == 0, + "full_dataset_init_size not multiple of item size"); + static_assert( + full_dataset_growth % item_size == 0, "full_dataset_growth not multiple of item size"); + + int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; + int num_items = ethash_find_largest_prime(num_items_upper_bound); + return num_items; + } -epoch_context_full* ethash_create_epoch_context_full(int epoch_number) noexcept -{ - return generic::create_epoch_context(build_light_cache, epoch_number, true); -} + epoch_context *ethash_create_epoch_context(int epoch_number) noexcept + { + return generic::create_epoch_context(build_light_cache, epoch_number, false); + } -void ethash_destroy_epoch_context_full(epoch_context_full* context) noexcept -{ - ethash_destroy_epoch_context(context); -} + epoch_context_full *ethash_create_epoch_context_full(int epoch_number) noexcept + { + return generic::create_epoch_context(build_light_cache, epoch_number, true); + } -void ethash_destroy_epoch_context(epoch_context* context) noexcept -{ - context->~epoch_context(); - std::free(context); -} + void ethash_destroy_epoch_context_full(epoch_context_full *context) noexcept + { + ethash_destroy_epoch_context(context); + } + void ethash_destroy_epoch_context(epoch_context *context) noexcept + { + context->~epoch_context(); + std::free(context); + } -ethash_result ethash_hash( - const epoch_context* context, const hash256* header_hash, uint64_t nonce) noexcept -{ - const hash512 seed = hash_seed(*header_hash, nonce); - const hash256 mix_hash = hash_kernel(*context, seed, calculate_dataset_item_1024); - return {hash_final(seed, mix_hash), mix_hash}; -} + ethash_result ethash_hash( + const epoch_context *context, const hash256 *header_hash, uint64_t nonce) noexcept + { + const hash512 seed = hash_seed(*header_hash, nonce); + const hash256 mix_hash = hash_kernel(*context, seed, calculate_dataset_item_1024); + return {hash_final(seed, mix_hash), mix_hash}; + } -bool ethash_verify_final_hash(const hash256* header_hash, const hash256* mix_hash, uint64_t nonce, - const hash256* boundary) noexcept -{ - const hash512 seed = hash_seed(*header_hash, nonce); - return is_less_or_equal(hash_final(seed, *mix_hash), *boundary); -} + bool ethash_verify_final_hash(const hash256 *header_hash, const hash256 *mix_hash, uint64_t nonce, + const hash256 *boundary) noexcept + { + const hash512 seed = hash_seed(*header_hash, nonce); + return is_less_or_equal(hash_final(seed, *mix_hash), *boundary); + } -bool ethash_verify(const epoch_context* context, const hash256* header_hash, - const hash256* mix_hash, uint64_t nonce, const hash256* boundary) noexcept -{ - const hash512 seed = hash_seed(*header_hash, nonce); - if (!is_less_or_equal(hash_final(seed, *mix_hash), *boundary)) - return false; + bool ethash_verify(const epoch_context *context, const hash256 *header_hash, + const hash256 *mix_hash, uint64_t nonce, const hash256 *boundary) noexcept + { + const hash512 seed = hash_seed(*header_hash, nonce); + if (!is_less_or_equal(hash_final(seed, *mix_hash), *boundary)) + return false; - const hash256 expected_mix_hash = hash_kernel(*context, seed, calculate_dataset_item_1024); - return is_equal(expected_mix_hash, *mix_hash); -} + const hash256 expected_mix_hash = hash_kernel(*context, seed, calculate_dataset_item_1024); + return is_equal(expected_mix_hash, *mix_hash); + } -} // extern "C" +} // extern "C" diff --git a/src/Native/libkawpow/ethash/ethash.h b/src/Native/libkawpow/ethash/ethash.h index 5d4230f6e..1b653ef8e 100644 --- a/src/Native/libkawpow/ethash/ethash.h +++ b/src/Native/libkawpow/ethash/ethash.h @@ -32,7 +32,8 @@ #endif #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /** @@ -46,99 +47,91 @@ extern "C" { #define ETHASH_FULL_DATASET_ITEM_SIZE 128 #define ETHASH_NUM_DATASET_ACCESSES 64 - -struct ethash_epoch_context -{ - const int epoch_number; - const int light_cache_num_items; - const union ethash_hash512* const light_cache; - const uint32_t* const l1_cache; - const int full_dataset_num_items; -}; - - -struct ethash_epoch_context_full; - - -struct ethash_result -{ - union ethash_hash256 final_hash; - union ethash_hash256 mix_hash; -}; - - -/** - * Calculates the number of items in the light cache for given epoch. - * - * This function will search for a prime number matching the criteria given - * by the Ethash so the execution time is not constant. It takes ~ 0.01 ms. - * - * @param epoch_number The epoch number. - * @return The number items in the light cache. - */ -int ethash_calculate_light_cache_num_items(int epoch_number) NOEXCEPT; - - -/** - * Calculates the number of items in the full dataset for given epoch. - * - * This function will search for a prime number matching the criteria given - * by the Ethash so the execution time is not constant. It takes ~ 0.05 ms. - * - * @param epoch_number The epoch number. - * @return The number items in the full dataset. - */ -int ethash_calculate_full_dataset_num_items(int epoch_number) NOEXCEPT; - -/** - * Calculates the epoch seed hash. - * @param epoch_number The epoch number. - * @return The epoch seed hash. - */ -union ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) NOEXCEPT; - - -EXPORT struct ethash_epoch_context* ethash_create_epoch_context(int epoch_number) NOEXCEPT; - -/** - * Creates the epoch context with the full dataset initialized. - * - * The memory for the full dataset is only allocated and marked as "not-generated". - * The items of the full dataset are generated on the fly when hit for the first time. - * - * The memory allocated in the context MUST be freed with ethash_destroy_epoch_context_full(). - * - * @param epoch_number The epoch number. - * @return Pointer to the context or null in case of memory allocation failure. - */ -EXPORT struct ethash_epoch_context_full* ethash_create_epoch_context_full(int epoch_number) NOEXCEPT; - -EXPORT void ethash_destroy_epoch_context(struct ethash_epoch_context* context) NOEXCEPT; - -EXPORT void ethash_destroy_epoch_context_full(struct ethash_epoch_context_full* context) NOEXCEPT; - - -/** - * Get global shared epoch context. - */ -const struct ethash_epoch_context* ethash_get_global_epoch_context(int epoch_number) NOEXCEPT; - -/** - * Get global shared epoch context with full dataset initialized. - */ -const struct ethash_epoch_context_full* ethash_get_global_epoch_context_full( - int epoch_number) NOEXCEPT; - - -struct ethash_result ethash_hash(const struct ethash_epoch_context* context, - const union ethash_hash256* header_hash, uint64_t nonce) NOEXCEPT; - -bool ethash_verify(const struct ethash_epoch_context* context, - const union ethash_hash256* header_hash, const union ethash_hash256* mix_hash, uint64_t nonce, - const union ethash_hash256* boundary) NOEXCEPT; -bool ethash_verify_final_hash(const union ethash_hash256* header_hash, - const union ethash_hash256* mix_hash, uint64_t nonce, - const union ethash_hash256* boundary) NOEXCEPT; + struct ethash_epoch_context + { + const int epoch_number; + const int light_cache_num_items; + const union ethash_hash512 *const light_cache; + const uint32_t *const l1_cache; + const int full_dataset_num_items; + }; + + struct ethash_epoch_context_full; + + struct ethash_result + { + union ethash_hash256 final_hash; + union ethash_hash256 mix_hash; + }; + + /** + * Calculates the number of items in the light cache for given epoch. + * + * This function will search for a prime number matching the criteria given + * by the Ethash so the execution time is not constant. It takes ~ 0.01 ms. + * + * @param epoch_number The epoch number. + * @return The number items in the light cache. + */ + int ethash_calculate_light_cache_num_items(int epoch_number) NOEXCEPT; + + /** + * Calculates the number of items in the full dataset for given epoch. + * + * This function will search for a prime number matching the criteria given + * by the Ethash so the execution time is not constant. It takes ~ 0.05 ms. + * + * @param epoch_number The epoch number. + * @return The number items in the full dataset. + */ + int ethash_calculate_full_dataset_num_items(int epoch_number) NOEXCEPT; + + /** + * Calculates the epoch seed hash. + * @param epoch_number The epoch number. + * @return The epoch seed hash. + */ + EXPORT union ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) NOEXCEPT; + + EXPORT struct ethash_epoch_context *ethash_create_epoch_context(int epoch_number) NOEXCEPT; + + /** + * Creates the epoch context with the full dataset initialized. + * + * The memory for the full dataset is only allocated and marked as "not-generated". + * The items of the full dataset are generated on the fly when hit for the first time. + * + * The memory allocated in the context MUST be freed with ethash_destroy_epoch_context_full(). + * + * @param epoch_number The epoch number. + * @return Pointer to the context or null in case of memory allocation failure. + */ + EXPORT struct ethash_epoch_context_full *ethash_create_epoch_context_full(int epoch_number) NOEXCEPT; + + EXPORT void ethash_destroy_epoch_context(struct ethash_epoch_context *context) NOEXCEPT; + + EXPORT void ethash_destroy_epoch_context_full(struct ethash_epoch_context_full *context) NOEXCEPT; + + /** + * Get global shared epoch context. + */ + const struct ethash_epoch_context *ethash_get_global_epoch_context(int epoch_number) NOEXCEPT; + + /** + * Get global shared epoch context with full dataset initialized. + */ + const struct ethash_epoch_context_full *ethash_get_global_epoch_context_full( + int epoch_number) NOEXCEPT; + + struct ethash_result ethash_hash(const struct ethash_epoch_context *context, + const union ethash_hash256 *header_hash, uint64_t nonce) NOEXCEPT; + + bool ethash_verify(const struct ethash_epoch_context *context, + const union ethash_hash256 *header_hash, const union ethash_hash256 *mix_hash, uint64_t nonce, + const union ethash_hash256 *boundary) NOEXCEPT; + bool ethash_verify_final_hash(const union ethash_hash256 *header_hash, + const union ethash_hash256 *mix_hash, uint64_t nonce, + const union ethash_hash256 *boundary) NOEXCEPT; #ifdef __cplusplus } diff --git a/src/Native/libkawpow/ethash/progpow.hpp b/src/Native/libkawpow/ethash/progpow.hpp index f1de8222e..59b07c3c6 100644 --- a/src/Native/libkawpow/ethash/progpow.hpp +++ b/src/Native/libkawpow/ethash/progpow.hpp @@ -27,42 +27,41 @@ namespace progpow { -using namespace ethash; // Include ethash namespace. + using namespace ethash; // Include ethash namespace. + /// The ProgPoW algorithm revision implemented as specified in the spec + /// https://github.com/ifdefelse/ProgPOW#change-history. + constexpr auto revision = "0.9.4"; -/// The ProgPoW algorithm revision implemented as specified in the spec -/// https://github.com/ifdefelse/ProgPOW#change-history. -constexpr auto revision = "0.9.4"; + constexpr int period_length = 3; + constexpr uint32_t num_regs = 32; + constexpr size_t num_lanes = 16; + constexpr int num_cache_accesses = 11; + constexpr int num_math_operations = 18; + constexpr size_t l1_cache_size = 16 * 1024; + constexpr size_t l1_cache_num_items = l1_cache_size / sizeof(uint32_t); -constexpr int period_length = 3; -constexpr uint32_t num_regs = 32; -constexpr size_t num_lanes = 16; -constexpr int num_cache_accesses = 11; -constexpr int num_math_operations = 18; -constexpr size_t l1_cache_size = 16 * 1024; -constexpr size_t l1_cache_num_items = l1_cache_size / sizeof(uint32_t); + result hashext(const epoch_context &context, int block_number, const hash256 &header_hash, + uint64_t nonce, const hash256 &mix_hash, const hash256 &boundary1, const hash256 &boundary2, int *retcode) noexcept; -extern "C" EXPORT result hashext(const epoch_context& context, int block_number, const hash256& header_hash, - uint64_t nonce, const hash256& mix_hash, const hash256& boundary1, const hash256& boundary2, int* retcode) noexcept; + extern "C" EXPORT result hash(const epoch_context &context, int block_number, const hash256 &header_hash, + uint64_t nonce) noexcept; -result hash(const epoch_context& context, int block_number, const hash256& header_hash, - uint64_t nonce) noexcept; + result hash(const epoch_context_full &context, int block_number, const hash256 &header_hash, + uint64_t nonce) noexcept; -result hash(const epoch_context_full& context, int block_number, const hash256& header_hash, - uint64_t nonce) noexcept; + extern "C" EXPORT bool verify(const epoch_context &context, int block_number, const hash256 &header_hash, + const hash256 &mix_hash, uint64_t nonce, const hash256 &boundary) noexcept; -extern "C" EXPORT bool verify(const epoch_context& context, int block_number, const hash256& header_hash, - const hash256& mix_hash, uint64_t nonce, const hash256& boundary) noexcept; + // bool light_verify(const char* str_header_hash, + // const char* str_mix_hash, const char* str_nonce, const char* str_boundary, char* str_final) noexcept; -//bool light_verify(const char* str_header_hash, -// const char* str_mix_hash, const char* str_nonce, const char* str_boundary, char* str_final) noexcept; + search_result search_light(const epoch_context &context, int block_number, + const hash256 &header_hash, const hash256 &boundary, uint64_t start_nonce, + size_t iterations) noexcept; -search_result search_light(const epoch_context& context, int block_number, - const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, - size_t iterations) noexcept; + search_result search(const epoch_context_full &context, int block_number, + const hash256 &header_hash, const hash256 &boundary, uint64_t start_nonce, + size_t iterations) noexcept; -search_result search(const epoch_context_full& context, int block_number, - const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, - size_t iterations) noexcept; - -} // namespace progpow +} // namespace progpow From a19e71429b419850438f9c8846412197ef001e85 Mon Sep 17 00:00:00 2001 From: ceedii Date: Wed, 5 Jul 2023 15:53:16 +0000 Subject: [PATCH 11/38] Add support for OctaSpace (OCTA) Optimmization of Ethereu family Fix multiple bugs in pool examples files --- build-windows.bat | 6 +- examples/beam_pool.json | 5 +- examples/callisto_pool.json | 2 +- examples/dash_pool.json | 5 +- examples/dash_pool_no_polling.json | 5 +- examples/digibyte_scrypt_pool.json | 5 +- examples/digibyte_sha256_pool.json | 5 +- examples/firo_pool.json | 13 +- examples/flo_pool.json | 3 +- examples/litecoin_dash_pool.json | 5 +- examples/litecoin_pool.json | 5 +- examples/monero_pool.json | 5 +- examples/octaspace_pool.json | 125 ++++ examples/pakcoin_pool.json | 5 +- examples/ravencoin_pool.json | 13 +- examples/veruscoin_pool.json | 5 +- examples/zcash_pool.json | 5 +- src/Miningcore.Tests/Miningcore.Tests.csproj | 167 ++--- src/Miningcore.sln | 72 +-- src/Miningcore/Blockchain/Beam/BeamJob.cs | 2 +- .../Blockchain/Bitcoin/BitcoinJob.cs | 2 +- .../Configuration/EthereumPoolConfigExtra.cs | 10 + .../Blockchain/Ethereum/EthereumConstants.cs | 31 + .../Ethereum/EthereumPayoutHandler.cs | 80 ++- .../Blockchain/Ethereum/EthereumPool.cs | 41 +- .../Blockchain/Progpow/ProgpowConstants.cs | 23 +- .../Blockchain/Progpow/ProgpowUtils.cs | 68 +- src/Miningcore/Configuration/ClusterConfig.cs | 3 + src/Miningcore/Miningcore.csproj | 282 ++++----- .../Postgres/Repositories/BlockRepository.cs | 13 + .../Persistence/Postgres/Scripts/createdb.sql | 5 +- .../Repositories/IBlockRepository.cs | 1 + src/Miningcore/coins.json | 32 +- src/Native/libcryptonight/libcryptonight.sln | 62 +- .../libcryptonight/libcryptonight.vcxproj | 582 +++++++++--------- src/Native/libetchash/libetchash.sln | 62 +- src/Native/libetchash/libetchash.vcxproj | 402 ++++++------ src/Native/libethhash/libethhash.sln | 62 +- src/Native/libethhash/libethhash.vcxproj | 402 ++++++------ src/Native/libkawpow/libkawpow.sln | 62 +- src/Native/libkawpow/liblibkawpow.vcxproj | 410 ++++++------ src/Native/libmultihash/libmultihash.sln | 62 +- .../net-core-test/net-core-test.csproj | 24 +- .../net-core-test/net-core-test.sln | 44 +- 44 files changed, 1762 insertions(+), 1461 deletions(-) create mode 100644 examples/octaspace_pool.json diff --git a/build-windows.bat b/build-windows.bat index f666e4608..87268cf1a 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/beam_pool.json b/examples/beam_pool.json index d87529602..0302f1108 100644 --- a/examples/beam_pool.json +++ b/examples/beam_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/callisto_pool.json b/examples/callisto_pool.json index 6a927c0f1..053411a57 100644 --- a/examples/callisto_pool.json +++ b/examples/callisto_pool.json @@ -9,7 +9,7 @@ "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": false, "banOnInvalidShares": false }, diff --git a/examples/dash_pool.json b/examples/dash_pool.json index 568bccf78..40d190f0c 100644 --- a/examples/dash_pool.json +++ b/examples/dash_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/dash_pool_no_polling.json b/examples/dash_pool_no_polling.json index 00f3a7357..0fb7f261c 100644 --- a/examples/dash_pool_no_polling.json +++ b/examples/dash_pool_no_polling.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/digibyte_scrypt_pool.json b/examples/digibyte_scrypt_pool.json index d083f7249..9e1a3960f 100644 --- a/examples/digibyte_scrypt_pool.json +++ b/examples/digibyte_scrypt_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/digibyte_sha256_pool.json b/examples/digibyte_sha256_pool.json index b225856a9..98ffff216 100644 --- a/examples/digibyte_sha256_pool.json +++ b/examples/digibyte_sha256_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/firo_pool.json b/examples/firo_pool.json index ca16ad990..1c912b624 100644 --- a/examples/firo_pool.json +++ b/examples/firo_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, @@ -77,9 +78,9 @@ "ports": { "3094": { "listenAddress": "0.0.0.0", - "difficulty": 0.1, + "difficulty": 1, "varDiff": { - "minDiff": 0.1, + "minDiff": 0.125, "maxDiff": null, "targetTime": 15, "retargetTime": 90, @@ -89,12 +90,12 @@ }, "3095": { "listenAddress": "0.0.0.0", - "difficulty": 0.1, + "difficulty": 1, "tls": true, "tlsPfxFile": "", "tlsPfxPassword": "password", "varDiff": { - "minDiff": 0.1, + "minDiff": 0.125, "maxDiff": null, "targetTime": 15, "retargetTime": 90, diff --git a/examples/flo_pool.json b/examples/flo_pool.json index 600c6dd7c..9b9082ac5 100644 --- a/examples/flo_pool.json +++ b/examples/flo_pool.json @@ -4,11 +4,12 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, diff --git a/examples/litecoin_dash_pool.json b/examples/litecoin_dash_pool.json index 56d85f6cf..c1acc3ec1 100644 --- a/examples/litecoin_dash_pool.json +++ b/examples/litecoin_dash_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/litecoin_pool.json b/examples/litecoin_pool.json index b2482b257..f7e43f86f 100644 --- a/examples/litecoin_pool.json +++ b/examples/litecoin_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/monero_pool.json b/examples/monero_pool.json index 6cbc780c8..dceda5051 100644 --- a/examples/monero_pool.json +++ b/examples/monero_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/octaspace_pool.json b/examples/octaspace_pool.json new file mode 100644 index 000000000..2d3cc887c --- /dev/null +++ b/examples/octaspace_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": "octa1", + "enabled": true, + "coin": "octaspace", + "address": "0xF8470A06f46Ab6340f94d8E153cB9c548744546E", + "rewardRecipients": [ + { + "type": "op", + "address": "0xF8470A06f46Ab6340f94d8E153cB9c548744546E", + "percentage": 1.0 + } + ], + "blockRefreshInterval": 120, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4073": { + "name": "GPU-SMALL", + "listenAddress": "*", + "difficulty": 0.1, + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + } + }, + "chainTypeOverride": "OctaSpace", + "daemons": [ + { + "host": "127.0.0.1", + "port": 8545, + "user": "", + "password": "" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.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/pakcoin_pool.json b/examples/pakcoin_pool.json index 85c65df0a..4ca78a997 100644 --- a/examples/pakcoin_pool.json +++ b/examples/pakcoin_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/ravencoin_pool.json b/examples/ravencoin_pool.json index 2b10c1fb1..a73f261a6 100644 --- a/examples/ravencoin_pool.json +++ b/examples/ravencoin_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, @@ -76,9 +77,9 @@ "ports": { "3094": { "listenAddress": "0.0.0.0", - "difficulty": 0.1, + "difficulty": 1, "varDiff": { - "minDiff": 0.1, + "minDiff": 0.125, "maxDiff": null, "targetTime": 15, "retargetTime": 90, @@ -88,12 +89,12 @@ }, "3095": { "listenAddress": "0.0.0.0", - "difficulty": 0.1, + "difficulty": 1, "tls": true, "tlsPfxFile": "", "tlsPfxPassword": "password", "varDiff": { - "minDiff": 0.1, + "minDiff": 0.125, "maxDiff": null, "targetTime": 15, "retargetTime": 90, diff --git a/examples/veruscoin_pool.json b/examples/veruscoin_pool.json index 97c709fb4..1117e642b 100644 --- a/examples/veruscoin_pool.json +++ b/examples/veruscoin_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/examples/zcash_pool.json b/examples/zcash_pool.json index fa6a5d3c8..dfbd848b7 100644 --- a/examples/zcash_pool.json +++ b/examples/zcash_pool.json @@ -4,16 +4,17 @@ "enableConsoleLog": true, "enableConsoleColors": true, "logFile": "", + "apiLogFile": "", "logBaseDirectory": "", "perPoolLogFile": false }, "banning": { - "manager": "integrated", + "manager": "Integrated", "banOnJunkReceive": true, "banOnInvalidShares": false }, "notifications": { - "enabled": true, + "enabled": false, "email": { "host": "smtp.example.com", "port": 587, diff --git a/src/Miningcore.Tests/Miningcore.Tests.csproj b/src/Miningcore.Tests/Miningcore.Tests.csproj index 96f0d3d14..673ae9989 100644 --- a/src/Miningcore.Tests/Miningcore.Tests.csproj +++ b/src/Miningcore.Tests/Miningcore.Tests.csproj @@ -1,80 +1,87 @@ - - - - true - - - - true - true - - - - net6.0 - false - AnyCPU - Miningcore.Tests - Miningcore.Tests - - - - AnyCPU - - - - AnyCPU - true - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - - - Always - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - - + + + + true + + + + true + true + + + + net6.0 + false + AnyCPU + Miningcore.Tests + Miningcore.Tests + + + + AnyCPU + + + + AnyCPU + true + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + Always + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + %(RecursiveDir)\%(Filename)%(Extension) + False + + + diff --git a/src/Miningcore.sln b/src/Miningcore.sln index e34a73fd7..3aa240d88 100644 --- a/src/Miningcore.sln +++ b/src/Miningcore.sln @@ -1,36 +1,36 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28729.10 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Miningcore", "Miningcore\Miningcore.csproj", "{A427248A-B5E1-4808-9883-BC2AD68EE997}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Miningcore.Tests", "Miningcore.Tests\Miningcore.Tests.csproj", "{DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{71672AAD-51F8-49EC-9EFD-E504D65A765A}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A427248A-B5E1-4808-9883-BC2AD68EE997}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A427248A-B5E1-4808-9883-BC2AD68EE997}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A427248A-B5E1-4808-9883-BC2AD68EE997}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A427248A-B5E1-4808-9883-BC2AD68EE997}.Release|Any CPU.Build.0 = Release|Any CPU - {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A0580AF2-6B0C-403F-9579-32D03A89CAC8} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28729.10 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Miningcore", "Miningcore\Miningcore.csproj", "{A427248A-B5E1-4808-9883-BC2AD68EE997}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Miningcore.Tests", "Miningcore.Tests\Miningcore.Tests.csproj", "{DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{71672AAD-51F8-49EC-9EFD-E504D65A765A}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A427248A-B5E1-4808-9883-BC2AD68EE997}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A427248A-B5E1-4808-9883-BC2AD68EE997}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A427248A-B5E1-4808-9883-BC2AD68EE997}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A427248A-B5E1-4808-9883-BC2AD68EE997}.Release|Any CPU.Build.0 = Release|Any CPU + {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCDE9CE6-84B8-42FE-AA55-2A3909A5E757}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A0580AF2-6B0C-403F-9579-32D03A89CAC8} + EndGlobalSection +EndGlobal diff --git a/src/Miningcore/Blockchain/Beam/BeamJob.cs b/src/Miningcore/Blockchain/Beam/BeamJob.cs index 7521f5ec0..e20403e40 100644 --- a/src/Miningcore/Blockchain/Beam/BeamJob.cs +++ b/src/Miningcore/Blockchain/Beam/BeamJob.cs @@ -49,7 +49,7 @@ public class BeamJob BigInteger solutionHashValue = new BigInteger(solutionHash, true, true); // calc share-diff - var shareDiff = (double) BigInteger.Divide(BeamConstants.BigMaxValue, solutionHashValue); + var shareDiff = (double) new BigRational(BeamConstants.BigMaxValue, solutionHashValue); var stratumDifficulty = context.Difficulty; var ratio = shareDiff / stratumDifficulty; diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 38ea3701e..0557ac076 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -593,7 +593,7 @@ public void Init(BlockTemplate blockTemplate, string jobId, { masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs(); - if((coin.Symbol == "RTM") || (coin.Symbol == "THOON") || (coin.Symbol == "YERB") || (coin.Symbol == "BTRM")) + if(coin.HasSmartNodes) { if(masterNodeParameters.Extra?.ContainsKey("smartnode") == true) { diff --git a/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs b/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs index 1ba4775aa..167015175 100644 --- a/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Ethereum/Configuration/EthereumPoolConfigExtra.cs @@ -13,6 +13,16 @@ public class EthereumPoolConfigExtra /// Useful to specify the real chain type when running geth /// public string ChainTypeOverride { get; set; } + + /// + /// There are several reports of bad actors taking advantage of the old "Ethash Stratum V1" protocol in order to perform multiple dangerous attacks like man-in-the-middle (MITM) attacks + /// 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. + /// "Ethash Stratum V1" protocol is disabled by default + /// + public bool enableEthashStratumV1 { get; set; } = false; /// /// getWork stream published via ZMQ diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs index a6792b703..b8c9fffca 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs @@ -63,6 +63,33 @@ public class EthOneConstants public const decimal BaseRewardInitial = 2.0m; } +// OCTA block reward distribution - +// https://docs.octa.space/cryptocurrency/monetary-policy +public class OctaSpaceConstants +{ + public const ulong TriangulumHardForkHeight = 10000000; + public const decimal TriangulumBlockReward = 1.0m; + public const ulong VegaHardForkHeight = 8000000; + public const decimal VegaBlockReward = 1.1m; + public const ulong BlackeyeHardForkHeight = 6000000; + public const decimal BlackeyeBlockReward = 1.2m; + public const ulong DneprHardForkHeight = 4000000; + public const decimal DneprBlockReward = 1.85m; + public const ulong MahasimHardForkHeight = 3000000; + public const decimal MahasimBlockReward = 2.3m; + public const ulong PolarisHardForkHeight = 2500000; + public const decimal PolarisBlockReward = 2.8m; + public const ulong SpringwaterHardForkHeight = 2000000; + public const decimal SpringwaterBlockReward = 3.0m; + public const ulong ZagamiHardForkHeight = 1500000; + public const decimal ZagamiBlockReward = 3.5m; + public const ulong OldenburgHardForkHeight = 1000000; + public const decimal OldenburgBlockReward = 4.0m; + public const ulong ArcturusHardForkHeight = 650000; + public const decimal ArcturusBlockReward = 5.0m; + public const decimal BaseRewardInitial = 6.5m; +} + public class PinkConstants { public const decimal BaseRewardInitial = 1.0m; @@ -96,6 +123,8 @@ public enum EthereumNetworkType MainPow = 10001, EtherOne = 4949, Pink = 10100, + OctaSpace = 800001, + OctaSpaceTestnet = 800002, Unknown = -1, } @@ -111,6 +140,8 @@ public enum GethChainType MainPow = 10001, EtherOne = 4949, Pink = 10100, + OctaSpace, + OctaSpaceTestnet, Unknown = -1, } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index bb98c7c7f..c02a9e6d7 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -120,25 +120,25 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, // There is a case scenario: // - https://github.com/oliverw/miningcore/issues/1583#issuecomment-1383009149 // - https://github.com/oliverw/miningcore/discussions/1103#discussioncomment-2121240) - // Where a miner with enough hash-rate power is able to mine two blocks simultaneously with the same `height` - // The first block is always an uncle and the second block is a regular block + // Where a miner with enough hash-rate power is able to mine multiple blocks simultaneously with the same `height` + // The last block is always a regular block and all the previous ones are all uncle blocks // We must handle that case carefully here, otherwise the PayoutManager will crash and no further blocks will be unlocked and no payment will be sent anymore. uint totalDuplicateBlock = await cf.Run(con => blockRepo.GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(block.BlockHeight), new[] { block.Status })); - uint totalDuplicateBlockBefore = 0; + uint totalDuplicateBlockAfter = 0; if(totalDuplicateBlock > 1) { - totalDuplicateBlockBefore = await cf.Run(con => blockRepo.GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(block.BlockHeight), new[] + totalDuplicateBlockAfter = await cf.Run(con => blockRepo.GetPoolDuplicateBlockAfterCountByPoolHeightNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(block.BlockHeight), new[] { block.Status }, block.Created)); } - if(totalDuplicateBlock > 1 && totalDuplicateBlockBefore < 1) + if(totalDuplicateBlock > 1 && totalDuplicateBlockAfter > 0) { logger.Info(() => $"[{LogCategory}] Got {totalDuplicateBlock} `{block.Status}` blocks with the same blockHeight: {block.BlockHeight}"); @@ -155,30 +155,37 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, else { var blockHashResponse = await rpcClient.ExecuteAsync(logger, EC.GetBlockByNumber, ct, new[] { (object) block.BlockHeight.ToStringHexWithPrefix(), true }); - var blockHash = blockHashResponse.Response.Hash; - var baseGas = blockHashResponse.Response.BaseFeePerGas; - var gasUsed = blockHashResponse.Response.GasUsed; + + var blockMiner = blockHashResponse.Response.Miner; + + // is it still block mined by us? + if(string.Equals(blockMiner, poolConfig.Address, StringComparison.OrdinalIgnoreCase)) + { + var blockHash = blockHashResponse.Response.Hash; + var baseGas = blockHashResponse.Response.BaseFeePerGas; + var gasUsed = blockHashResponse.Response.GasUsed; - var burnedFee = (decimal) 0; - if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink") - burnedFee = (baseGas * gasUsed / EthereumConstants.Wei); + var burnedFee = (decimal) 0; + if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink") + burnedFee = (baseGas * gasUsed / EthereumConstants.Wei); - block.Hash = blockHash; - block.Status = BlockStatus.Confirmed; - block.ConfirmationProgress = 1; - block.BlockHeight = (ulong) blockInfo.Height; - block.Reward = GetBaseBlockReward(chainType, block.BlockHeight); // base reward - block.Type = EthereumConstants.BlockTypeBlock; + block.Hash = blockHash; + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + block.BlockHeight = (ulong) blockInfo.Height; + block.Reward = GetBaseBlockReward(chainType, block.BlockHeight); // base reward + block.Type = EthereumConstants.BlockTypeBlock; - if(extraConfig?.KeepUncles == false) - block.Reward += blockInfo.Uncles.Length * (block.Reward / 32); // uncle rewards + if(extraConfig?.KeepUncles == false) + block.Reward += blockInfo.Uncles.Length * (block.Reward / 32); // uncle rewards - if(extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0) - block.Reward += await GetTxRewardAsync(blockInfo, ct) - burnedFee; + if(extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0) + block.Reward += await GetTxRewardAsync(blockInfo, ct) - burnedFee; - logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); - messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } } } @@ -291,7 +298,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation // ensure we have 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") && + 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") && (infoResponse.Error != null || string.IsNullOrEmpty(infoResponse.Response) || infoResponse.Response.IntegralFromHex() < EthereumConstants.MinPayoutPeerCount)) { @@ -401,6 +408,31 @@ internal static decimal GetBaseBlockReward(GethChainType chainType, ulong height return UbiqConstants.BaseRewardInitial; + case GethChainType.OctaSpace: + case GethChainType.OctaSpaceTestnet: + if(height >= OctaSpaceConstants.TriangulumHardForkHeight) + return OctaSpaceConstants.TriangulumBlockReward; + if(height >= OctaSpaceConstants.VegaHardForkHeight) + return OctaSpaceConstants.VegaBlockReward; + if(height >= OctaSpaceConstants.BlackeyeHardForkHeight) + return OctaSpaceConstants.BlackeyeBlockReward; + if(height >= OctaSpaceConstants.DneprHardForkHeight) + return OctaSpaceConstants.DneprBlockReward; + if(height >= OctaSpaceConstants.MahasimHardForkHeight) + return OctaSpaceConstants.MahasimBlockReward; + if(height >= OctaSpaceConstants.PolarisHardForkHeight) + return OctaSpaceConstants.PolarisBlockReward; + if(height >= OctaSpaceConstants.SpringwaterHardForkHeight) + return OctaSpaceConstants.SpringwaterBlockReward; + if(height >= OctaSpaceConstants.ZagamiHardForkHeight) + return OctaSpaceConstants.ZagamiBlockReward; + if(height >= OctaSpaceConstants.OldenburgHardForkHeight) + return OctaSpaceConstants.OldenburgBlockReward; + if(height >= OctaSpaceConstants.ArcturusHardForkHeight) + return OctaSpaceConstants.ArcturusBlockReward; + + return OctaSpaceConstants.BaseRewardInitial; + default: throw new Exception("Unable to determine block reward: Unsupported chain type"); } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs index 660bf163d..6d7420522 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPool.cs @@ -4,7 +4,9 @@ using Autofac; using AutoMapper; using Microsoft.IO; +using Miningcore.Blockchain.Ethereum.Configuration; using Miningcore.Configuration; +using Miningcore.Extensions; using Miningcore.JsonRpc; using Miningcore.Messaging; using Miningcore.Mining; @@ -37,6 +39,7 @@ public EthereumPool(IComponentContext ctx, private EthereumJobManager manager; private EthereumCoinTemplate coin; + private EthereumPoolConfigExtra extraPoolConfig; #region // Protocol V2 handlers - https://github.com/nicehash/Specifications/blob/master/EthereumStratum_NiceHash_v1.0.0.txt @@ -361,6 +364,7 @@ private async Task SendWork(EthereumWorkerContext context, StratumConnection con public override void Configure(PoolConfig pc, ClusterConfig cc) { coin = pc.Template.As(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); base.Configure(pc, cc); } @@ -483,6 +487,11 @@ protected override async Task OnRequestAsync(StratumConnection connection, break; // V1 Stratum methods + // There are several reports of bad actors taking advantage of the old "Ethash Stratum V1" protocol in order to perform multiple dangerous attacks like man-in-the-middle (MITM) attacks + // 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. case EthereumStratumMethods.SubmitLogin: context.ProtocolVersion = 1; // lock in protocol version @@ -490,15 +499,35 @@ protected override async Task OnRequestAsync(StratumConnection connection, break; case EthereumStratumMethods.GetWork: - EnsureProtocolVersion(context, 1); - - await OnGetWorkAsync(connection, tsRequest); + if(!extraPoolConfig.enableEthashStratumV1) + { + logger.Info(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); + } + else + { + EnsureProtocolVersion(context, 1); + + logger.Warn(() => $"Use of Ethash Stratum V1 method: {request.Method}"); + await OnGetWorkAsync(connection, tsRequest); + } break; case EthereumStratumMethods.SubmitWork: - EnsureProtocolVersion(context, 1); - - await OnSubmitAsync(connection, tsRequest, ct, true); + if(!extraPoolConfig.enableEthashStratumV1) + { + logger.Info(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); + } + else + { + EnsureProtocolVersion(context, 1); + + logger.Warn(() => $"Use of Ethash Stratum V1 method: {request.Method}"); + await OnSubmitAsync(connection, tsRequest, ct, true); + } break; case EthereumStratumMethods.SubmitHashrate: diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs b/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs index de695d720..8d8efb811 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs @@ -1,22 +1,25 @@ using System.Globalization; using System.Numerics; +using Miningcore.Util; namespace Miningcore.Blockchain.Progpow; -public class RavencoinConstants +public class FiroConstants { - public const int EpochLength = 7500; - public static readonly Org.BouncyCastle.Math.BigInteger Diff1B = new Org.BouncyCastle.Math.BigInteger("00ff000000000000000000000000000000000000000000000000000000", 16); - public static readonly BigInteger Diff1 = BigInteger.Parse("00ff000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); - public const int TargetPaddingLength = 32; + public const int EpochLength = 1300; + 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 FiroConstants +public class RavencoinConstants { - public const int EpochLength = 1300; - public static readonly Org.BouncyCastle.Math.BigInteger Diff1B = new Org.BouncyCastle.Math.BigInteger("00ffff0000000000000000000000000000000000000000000000000000", 16); - public static readonly BigInteger Diff1 = BigInteger.Parse("00ffff0000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber); - public const int TargetPaddingLength = 32; + public const int EpochLength = 7500; + 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/ProgpowUtils.cs b/src/Miningcore/Blockchain/Progpow/ProgpowUtils.cs index ea878a1b9..d902f745d 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowUtils.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowUtils.cs @@ -1,5 +1,5 @@ -using Miningcore.Extensions; -using Org.BouncyCastle.Math; +using System.Globalization; +using System.Numerics; namespace Miningcore.Blockchain.Progpow; @@ -7,45 +7,57 @@ public static class ProgpowUtils { public static string FiroEncodeTarget(double difficulty) { - string result; - var diff = BigInteger.ValueOf((long) (difficulty * 255d)); - var quotient = FiroConstants.Diff1B.Divide(diff).Multiply(BigInteger.ValueOf(255)); - var bytes = quotient.ToByteArray().AsSpan(); - Span padded = stackalloc byte[FiroConstants.TargetPaddingLength]; + difficulty = 1.0 / difficulty; - var padLength = FiroConstants.TargetPaddingLength - bytes.Length; + BigInteger NewTarget; + BigInteger DecimalDiff; + BigInteger DecimalTarget; - if(padLength > 0) + NewTarget = BigInteger.Multiply(FiroConstants.Diff1B, new BigInteger(difficulty)); + + string StringDiff = difficulty.ToString(CultureInfo.InvariantCulture); + int DecimalOffset = StringDiff.IndexOf("."); + if(DecimalOffset > -1) { - bytes.CopyTo(padded.Slice(padLength, bytes.Length)); - result = padded.ToHexString(0, FiroConstants.TargetPaddingLength); - } + int Precision = (StringDiff.Length - 1) - DecimalOffset; + DecimalDiff = BigInteger.Parse(StringDiff.Substring(DecimalOffset + 1)); + DecimalTarget = BigInteger.Multiply(FiroConstants.Diff1B, DecimalDiff); - else - result = bytes.ToHexString(0, FiroConstants.TargetPaddingLength); + string s = DecimalTarget.ToString(); + s = s.Substring(0, s.Length - Precision); + + DecimalTarget = BigInteger.Parse(s); + NewTarget += DecimalTarget; + } - return result; + return string.Format("{0:x64}", NewTarget); } public static string RavencoinEncodeTarget(double difficulty) { - string result; - var diff = BigInteger.ValueOf((long) (difficulty * 255d)); - var quotient = RavencoinConstants.Diff1B.Divide(diff).Multiply(BigInteger.ValueOf(255)); - var bytes = quotient.ToByteArray().AsSpan(); - Span padded = stackalloc byte[RavencoinConstants.TargetPaddingLength]; + difficulty = 1.0 / difficulty; - var padLength = RavencoinConstants.TargetPaddingLength - bytes.Length; + BigInteger NewTarget; + BigInteger DecimalDiff; + BigInteger DecimalTarget; - if(padLength > 0) + NewTarget = BigInteger.Multiply(RavencoinConstants.Diff1B, new BigInteger(difficulty)); + + string StringDiff = difficulty.ToString(CultureInfo.InvariantCulture); + int DecimalOffset = StringDiff.IndexOf("."); + if(DecimalOffset > -1) { - bytes.CopyTo(padded.Slice(padLength, bytes.Length)); - result = padded.ToHexString(0, RavencoinConstants.TargetPaddingLength); - } + int Precision = (StringDiff.Length - 1) - DecimalOffset; + DecimalDiff = BigInteger.Parse(StringDiff.Substring(DecimalOffset + 1)); + DecimalTarget = BigInteger.Multiply(RavencoinConstants.Diff1B, DecimalDiff); - else - result = bytes.ToHexString(0, RavencoinConstants.TargetPaddingLength); + string s = DecimalTarget.ToString(); + s = s.Substring(0, s.Length - Precision); + + DecimalTarget = BigInteger.Parse(s); + NewTarget += DecimalTarget; + } - return result; + return string.Format("{0:x64}", NewTarget); } } \ No newline at end of file diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 5d3ea3702..5fa5568a3 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -197,6 +197,9 @@ public class BitcoinNetworkParams [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasMasterNodes { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool HasSmartNodes { get; set; } [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool HasBrokenSendMany { get; set; } = false; diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 04d397bd7..5f9766bb3 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -1,141 +1,141 @@ - - - Exe - net6.0 - Miningcore - Miningcore - true - true - true - - - - true - true - true - - - - - <_Parameter1>$(AssemblyName).Tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\libs\WebSocketManager.dll - - - ..\..\libs\WebSocketManager.Common.dll - - - ..\..\libs\ZeroMQ.dll - - - - - - PreserveNewest - - - - - - - - %(RecursiveDir)%(FileName)%(Extension) - PreserveNewest - - - - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - - - + + + Exe + net6.0 + Miningcore + Miningcore + true + true + true + + + + true + true + true + + + + + <_Parameter1>$(AssemblyName).Tests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\libs\WebSocketManager.dll + + + ..\..\libs\WebSocketManager.Common.dll + + + ..\..\libs\ZeroMQ.dll + + + + + + PreserveNewest + + + + + + + + %(RecursiveDir)%(FileName)%(Extension) + PreserveNewest + + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs index 9880f9b7f..da17b0538 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs @@ -152,4 +152,17 @@ 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 + })); + } } diff --git a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql index 5cc5f1030..64b5258db 100644 --- a/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql +++ b/src/Miningcore/Persistence/Postgres/Scripts/createdb.sql @@ -33,12 +33,11 @@ CREATE TABLE blocks reward decimal(28,12) NULL, source TEXT NULL, hash TEXT NULL, - created TIMESTAMPTZ NOT NULL, - - CONSTRAINT BLOCKS_POOL_HEIGHT UNIQUE (poolid, blockheight, type) DEFERRABLE INITIALLY DEFERRED + created TIMESTAMPTZ NOT NULL ); CREATE INDEX IDX_BLOCKS_POOL_BLOCK_STATUS on blocks(poolid, blockheight, status); +CREATE INDEX IDX_BLOCKS_POOL_BLOCK_TYPE on blocks(poolid, blockheight, type); CREATE TABLE balances ( diff --git a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs index 3840a96c2..abb31884c 100644 --- a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs @@ -18,4 +18,5 @@ public interface IBlockRepository 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); } diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 3cac0efca..5d3f61a28 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -2169,6 +2169,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "foundersRewardAddress": [ "RTtyQU6DoSuNWetT4WUem5qXP5jNYGpwat" ], @@ -2353,6 +2354,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "foundersRewardAddress": [ "BanxgMPcMpXnuWQ2ogfQqEkwwVtjhAhXBR" ], @@ -2850,6 +2852,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "shareMultiplier": 65536, "explorerBlockLink": "http://rtm.timyg.org:6950/block/$height$", "explorerTxLink": "http://rtm.timyg.org:6950/tx/{0}", @@ -3438,6 +3441,7 @@ }, "hasFounderFee": true, "hasMasterNodes": true, + "hasSmartNodes": true, "shareMultiplier": 65536, "explorerBlockLink": "https://explorer.yerbas.org/block/$height$", "explorerTxLink": "https://explorer.yerbas.org/tx/{0}", @@ -3787,11 +3791,11 @@ "name": "Veruscoin", "symbol": "VRSC", "family": "equihash", - "website": "", - "market": "", - "twitter": "", - "telegram": "", - "discord": "", + "website": "https://verus.io/", + "market": "https://coinmarketcap.com/currencies/veruscoin/", + "twitter": "https://twitter.com/veruscoin", + "telegram": "https://t.me/veruscommunity", + "discord": "https://discord.com/invite/VRKMP2S", "networks": { "main": { "diff1": "00000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", @@ -4451,6 +4455,24 @@ "explorerTxLink": "https://blockscout.etherone.one/tx/{0}", "explorerAccountLink": "https://blockscout.etherone.one/address/{0}", "ethasher": "ethash" + }, + "octaspace": { + "name": "OctaSpace", + "canonicalName": "Octa.Space", + "symbol": "OCTA", + "family": "ethereum", + "website": "https://octa.space/", + "market": "https://coinmarketcap.com/currencies/octaspace/", + "twitter": "https://twitter.com/octa_space", + "telegram": "https://t.me/octa_space", + "discord": "https://discord.gg/octaspace", + "explorerBlockLinks": { + "block": "https://explorer.octa.space/block/$height$", + "uncle": "https://explorer.octa.space/block/$height$" + }, + "explorerTxLink": "https://explorer.octa.space/tx/{0}", + "explorerAccountLink": "https://explorer.octa.space/address/{0}", + "ethasher": "ethash" }, "pinkchain": { "name": "PinkChain", diff --git a/src/Native/libcryptonight/libcryptonight.sln b/src/Native/libcryptonight/libcryptonight.sln index 21f6ec47e..48150ec16 100644 --- a/src/Native/libcryptonight/libcryptonight.sln +++ b/src/Native/libcryptonight/libcryptonight.sln @@ -1,31 +1,31 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26720.2 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcryptonight", "libcryptonight.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {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 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26720.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcryptonight", "libcryptonight.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libcryptonight/libcryptonight.vcxproj b/src/Native/libcryptonight/libcryptonight.vcxproj index 969110f4b..1defb99fb 100644 --- a/src/Native/libcryptonight/libcryptonight.vcxproj +++ b/src/Native/libcryptonight/libcryptonight.vcxproj @@ -1,292 +1,292 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {2DE74E14-BF6D-4046-951B-8EBC8A1BA009} - Win32Proj - netmultihashnative - 10.0 - libcryptonight - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) - - - - NotUsing - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL - true - MultiThreadedDebug - stdcpp14 - xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) - Default - - - Windows - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - NotUsing - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL - true - MultiThreadedDebug - stdcpp14 - xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) - Default - - - Windows - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - NotUsing - Level3 - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL - true - MultiThreaded - stdcpp14 - xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) - Default - - - Windows - true - true - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - NotUsing - Level3 - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL - true - MultiThreaded - stdcpp14 - xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) - Default - - - Windows - true - true - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Document - - - Document - - - Document - - - Document - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009} + Win32Proj + netmultihashnative + 10.0 + libcryptonight + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + NotUsing + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL + true + MultiThreadedDebug + stdcpp14 + xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) + Default + + + Windows + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL + true + MultiThreadedDebug + stdcpp14 + xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) + Default + + + Windows + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL + true + MultiThreaded + stdcpp14 + xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) + Default + + + Windows + true + true + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;__AES__;CPU_INTEL + true + MultiThreaded + stdcpp14 + xmrig\3rdparty\argon2\include;xmrig\3rdparty\argon2\lib;xmrig;xmrig-override;(AdditionalIncludeDirectories) + Default + + + Windows + true + true + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + + + Document + + + Document + + + Document + + + + + + \ No newline at end of file diff --git a/src/Native/libetchash/libetchash.sln b/src/Native/libetchash/libetchash.sln index 9264baf45..3490adb5f 100644 --- a/src/Native/libetchash/libetchash.sln +++ b/src/Native/libetchash/libetchash.sln @@ -1,31 +1,31 @@ - -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}") = "libmultihash", "libetchash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {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 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} - EndGlobalSection -EndGlobal + +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}") = "libmultihash", "libetchash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libetchash/libetchash.vcxproj b/src/Native/libetchash/libetchash.vcxproj index 22b28c95d..160fd6567 100644 --- a/src/Native/libetchash/libetchash.vcxproj +++ b/src/Native/libetchash/libetchash.vcxproj @@ -1,202 +1,202 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} - Win32Proj - netmultihashnative - 10.0 - libetchash - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libethhash\windows\lib\x64;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libetchash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libethhash\windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libethhash/libethhash.sln b/src/Native/libethhash/libethhash.sln index 0e8913fb0..2b0ae5130 100644 --- a/src/Native/libethhash/libethhash.sln +++ b/src/Native/libethhash/libethhash.sln @@ -1,31 +1,31 @@ - -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}") = "libmultihash", "libethhash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {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 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} - EndGlobalSection -EndGlobal + +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}") = "libmultihash", "libethhash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libethhash/libethhash.vcxproj b/src/Native/libethhash/libethhash.vcxproj index fe704fc14..dfb2f4a9d 100644 --- a/src/Native/libethhash/libethhash.vcxproj +++ b/src/Native/libethhash/libethhash.vcxproj @@ -1,202 +1,202 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} - Win32Proj - netmultihashnative - 10.0 - libethhash - - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libethhash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libkawpow/libkawpow.sln b/src/Native/libkawpow/libkawpow.sln index 1d1e6f955..854290279 100644 --- a/src/Native/libkawpow/libkawpow.sln +++ b/src/Native/libkawpow/libkawpow.sln @@ -1,31 +1,31 @@ - -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", "liblibkawpow.vcxproj", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - 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 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} - EndGlobalSection -EndGlobal + +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", "liblibkawpow.vcxproj", "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + 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 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libkawpow/liblibkawpow.vcxproj b/src/Native/libkawpow/liblibkawpow.vcxproj index 9d05a07b3..29283c5a1 100644 --- a/src/Native/libkawpow/liblibkawpow.vcxproj +++ b/src/Native/libkawpow/liblibkawpow.vcxproj @@ -1,206 +1,206 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} - Win32Proj - netmultihashnative - 10.0 - libkawpow - - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - true - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) - - - false - $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) - $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreadedDebug - stdcpp14 - - - Windows - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - - - Level3 - MaxSpeed - true - true - SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS - true - MultiThreaded - stdcpp14 - - - Windows - true - true - true - Ws2_32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libkawpow + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)windows\include\libsodium;$(ProjectDir)windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libmultihash/libmultihash.sln b/src/Native/libmultihash/libmultihash.sln index ba9d798f3..00f72cff9 100644 --- a/src/Native/libmultihash/libmultihash.sln +++ b/src/Native/libmultihash/libmultihash.sln @@ -1,31 +1,31 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26720.2 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmultihash", "libmultihash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {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 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26720.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmultihash", "libmultihash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libmultihash/net-core-test/net-core-test.csproj b/src/Native/libmultihash/net-core-test/net-core-test.csproj index df36a150f..a86551bae 100644 --- a/src/Native/libmultihash/net-core-test/net-core-test.csproj +++ b/src/Native/libmultihash/net-core-test/net-core-test.csproj @@ -1,12 +1,12 @@ - - - - Exe - netcoreapp1.1 - - - - True - - - + + + + Exe + netcoreapp1.1 + + + + True + + + diff --git a/src/Native/libmultihash/net-core-test/net-core-test.sln b/src/Native/libmultihash/net-core-test/net-core-test.sln index 58e76bdeb..5a43b9ee3 100644 --- a/src/Native/libmultihash/net-core-test/net-core-test.sln +++ b/src/Native/libmultihash/net-core-test/net-core-test.sln @@ -1,22 +1,22 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26430.16 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "net-core-test", "net-core-test.csproj", "{23D6F17A-2FA5-4614-812B-864387322994}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {23D6F17A-2FA5-4614-812B-864387322994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {23D6F17A-2FA5-4614-812B-864387322994}.Debug|Any CPU.Build.0 = Debug|Any CPU - {23D6F17A-2FA5-4614-812B-864387322994}.Release|Any CPU.ActiveCfg = Release|Any CPU - {23D6F17A-2FA5-4614-812B-864387322994}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "net-core-test", "net-core-test.csproj", "{23D6F17A-2FA5-4614-812B-864387322994}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {23D6F17A-2FA5-4614-812B-864387322994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23D6F17A-2FA5-4614-812B-864387322994}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23D6F17A-2FA5-4614-812B-864387322994}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23D6F17A-2FA5-4614-812B-864387322994}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal From 3836fd8bf9b6ec8b85c303dbe3f5750354e04447 Mon Sep 17 00:00:00 2001 From: ceedii Date: Thu, 6 Jul 2023 15:18:19 +0000 Subject: [PATCH 12/38] Fix multiple bugs in pool examples files --- examples/firo_pool.json | 4 ++-- examples/ravencoin_pool.json | 4 ++-- examples/veruscoin_pool.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/firo_pool.json b/examples/firo_pool.json index 1c912b624..e67494aa6 100644 --- a/examples/firo_pool.json +++ b/examples/firo_pool.json @@ -48,7 +48,7 @@ "enabled": true, "coin": "firo", "address": "aFkp9i2yxNyRW17uX4XLDStnPoguwJ6tuL", - "GBTArgs": { + "GBTArgs": [{ "capabilities": [ "coinbasetxn", "workid", @@ -57,7 +57,7 @@ "rules": [ "segwit" ] - }, + }], "rewardRecipients": [ { "type": "op", diff --git a/examples/ravencoin_pool.json b/examples/ravencoin_pool.json index a73f261a6..91101623c 100644 --- a/examples/ravencoin_pool.json +++ b/examples/ravencoin_pool.json @@ -48,7 +48,7 @@ "enabled": true, "coin": "ravencoin", "address": "mxR4ic4Q32giqfcYqQGxDteGhzkjgA2eX6", - "GBTArgs": { + "GBTArgs": [{ "capabilities": [ "coinbasetxn", "workid", @@ -57,7 +57,7 @@ "rules": [ "segwit" ] - }, + }], "rewardRecipients": [ { "type": "op", diff --git a/examples/veruscoin_pool.json b/examples/veruscoin_pool.json index 1117e642b..8be25ccd5 100644 --- a/examples/veruscoin_pool.json +++ b/examples/veruscoin_pool.json @@ -49,7 +49,7 @@ "coin": "veruscoin", "address": "RHux2fYMyxMG4W5F2Va436cANsR47JUvTE", "z-address": "zs1eqnvc3nfd6wz5m65n7ygc9pkqzpx8zwzlz6epx8rvsvdu88k9anapu5gcg8ekq2fzsl3654fzc2", - "GBTArgs": { + "GBTArgs": [{ "capabilities": [ "coinbasetxn", "workid", @@ -58,7 +58,7 @@ "rules": [ "segwit" ] - }, + }], "rewardRecipients": [ { "type": "op", From 003270856efbcc73fc61efe49d59619f0da93e79 Mon Sep 17 00:00:00 2001 From: ceedii Date: Tue, 11 Jul 2023 00:52:37 +0000 Subject: [PATCH 13/38] Remove shielding for Veruscoin since it's deprecated feature in the node --- examples/veruscoin_pool.json | 1 - src/Miningcore/coins.json | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/veruscoin_pool.json b/examples/veruscoin_pool.json index 8be25ccd5..89ae7b702 100644 --- a/examples/veruscoin_pool.json +++ b/examples/veruscoin_pool.json @@ -48,7 +48,6 @@ "enabled": true, "coin": "veruscoin", "address": "RHux2fYMyxMG4W5F2Va436cANsR47JUvTE", - "z-address": "zs1eqnvc3nfd6wz5m65n7ygc9pkqzpx8zwzlz6epx8rvsvdu88k9anapu5gcg8ekq2fzsl3654fzc2", "GBTArgs": [{ "capabilities": [ "coinbasetxn", diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 5d3f61a28..2520acf5b 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -3855,8 +3855,8 @@ "payFoundersReward": false } }, - "usesZCashAddressFormat": true, - "useBitcoinPayoutHandler": false, + "usesZCashAddressFormat": false, + "useBitcoinPayoutHandler": true, "explorerBlockLink": "https://explorer.veruscoin.io/block/$height$", "explorerTxLink": "https://explorer.veruscoin.io/tx/{0}", "explorerAccountLink": "https://explorer.veruscoin.io/address/{0}" @@ -4495,7 +4495,7 @@ "ubiq": { "name": "Ubiq", "canonicalName": "Ubiq", - "symbol": "UBIQ", + "symbol": "UBQ", "family": "ethereum", "website": "https://ubiqsmart.com/", "market": "", From 98220d410ff4d624bc7e09389e342332ea204a7e Mon Sep 17 00:00:00 2001 From: ceedii Date: Fri, 25 Aug 2023 14:14:59 +0000 Subject: [PATCH 14/38] Fix VRSC address validation --- .../Blockchain/Equihash/EquihashJobManager.cs | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index d7b9df719..129d798d4 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -202,16 +202,26 @@ public override async Task ValidateAddressAsync(string address, Cancellati { if(string.IsNullOrEmpty(address)) return false; - - // handle t-addr - if(await base.ValidateAddressAsync(address, ct)) - return true; - - // handle z-addr - var result = await rpc.ExecuteAsync(logger, - EquihashCommands.ZValidateAddress, ct, new[] { address }); - - return result.Response is {IsValid: true}; + + switch(coin.Symbol) + { + case "VRSC": + // handle t-addr + if(await base.ValidateAddressAsync(address, ct)) + return true; + + return false; + default: + // handle t-addr + if(await base.ValidateAddressAsync(address, ct)) + return true; + + // handle z-addr + var result = await rpc.ExecuteAsync(logger, + EquihashCommands.ZValidateAddress, ct, new[] { address }); + + return result.Response is {IsValid: true}; + } } public object[] GetSubscriberData(StratumConnection worker) From 8884a765fd3bc121095e3a85da38b5f06755af4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:28:57 +0000 Subject: [PATCH 15/38] Bump FluentValidation.AspNetCore in /src/Miningcore Bumps [FluentValidation.AspNetCore](https://github.com/FluentValidation/FluentValidation.AspNetCore) from 11.2.2 to 11.3.0. - [Release notes](https://github.com/FluentValidation/FluentValidation.AspNetCore/releases) - [Commits](https://github.com/FluentValidation/FluentValidation.AspNetCore/compare/11.2.2...11.3.0) --- updated-dependencies: - dependency-name: FluentValidation.AspNetCore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 5f9766bb3..86ef11895 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -62,7 +62,7 @@ - + From 99b5794c420464ec44d3d8a8acaff744ecef1fbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:29:06 +0000 Subject: [PATCH 16/38] Bump Microsoft.Extensions.Configuration.Json in /src/Miningcore Bumps [Microsoft.Extensions.Configuration.Json](https://github.com/dotnet/runtime) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v6.0.0...v7.0.0) --- updated-dependencies: - dependency-name: Microsoft.Extensions.Configuration.Json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 5f9766bb3..eb9153227 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -68,7 +68,7 @@ - + From 859fb1a66d6c40d96d2ab650322c443772676c6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:29:14 +0000 Subject: [PATCH 17/38] Bump NLog.Extensions.Hosting from 5.1.0 to 5.3.3 in /src/Miningcore Bumps [NLog.Extensions.Hosting](https://github.com/NLog/NLog.Extensions.Logging) from 5.1.0 to 5.3.3. - [Release notes](https://github.com/NLog/NLog.Extensions.Logging/releases) - [Changelog](https://github.com/NLog/NLog.Extensions.Logging/blob/master/CHANGELOG.MD) - [Commits](https://github.com/NLog/NLog.Extensions.Logging/compare/v5.1.0...v5.3.3) --- updated-dependencies: - dependency-name: NLog.Extensions.Hosting dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 5f9766bb3..f39774105 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -58,7 +58,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 8565816812c5ec13d108126cf9d9abc5624a535c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:29:18 +0000 Subject: [PATCH 18/38] Bump NSwag.AspNetCore from 13.17.0 to 13.20.0 in /src/Miningcore Bumps [NSwag.AspNetCore](https://github.com/RicoSuter/NSwag) from 13.17.0 to 13.20.0. - [Release notes](https://github.com/RicoSuter/NSwag/releases) - [Changelog](https://github.com/RicoSuter/NSwag/blob/master/CHANGELOG.md) - [Commits](https://github.com/RicoSuter/NSwag/compare/v13.17.0...v13.20.0) --- updated-dependencies: - dependency-name: NSwag.AspNetCore dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 5f9766bb3..5b7fc88e4 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -52,7 +52,7 @@ - + all From 13be662d06e174ebda0095e38f1b92a19b691910 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:29:18 +0000 Subject: [PATCH 19/38] Bump AspNetCoreRateLimit from 4.0.2 to 5.0.0 in /src/Miningcore Bumps [AspNetCoreRateLimit](https://github.com/stefanprodan/AspNetCoreRateLimit) from 4.0.2 to 5.0.0. - [Release notes](https://github.com/stefanprodan/AspNetCoreRateLimit/releases) - [Commits](https://github.com/stefanprodan/AspNetCoreRateLimit/compare/4.0.2...v5.0.0) --- updated-dependencies: - dependency-name: AspNetCoreRateLimit dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 5f9766bb3..12dff5cef 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -41,7 +41,7 @@ - + From 58701a92e4c9b2594a4f2c93e8277fabe2be7923 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Aug 2023 03:35:10 +0000 Subject: [PATCH 20/38] Bump JetBrains.Annotations from 2022.3.1 to 2023.2.0 in /src/Miningcore Bumps [JetBrains.Annotations](https://github.com/JetBrains/JetBrains.Annotations) from 2022.3.1 to 2023.2.0. - [Commits](https://github.com/JetBrains/JetBrains.Annotations/compare/v2022.3.1...v2023.2.0) --- updated-dependencies: - dependency-name: JetBrains.Annotations dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 86ef11895..8bbe0ba79 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -64,7 +64,7 @@ - + From 34b128545bbd6fb74d7f857c48f56f77f9225baa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Aug 2023 03:36:15 +0000 Subject: [PATCH 21/38] Bump Microsoft.Extensions.Caching.Memory in /src/Miningcore Bumps [Microsoft.Extensions.Caching.Memory](https://github.com/dotnet/runtime) from 6.0.1 to 7.0.0. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v6.0.1...v7.0.0) --- updated-dependencies: - dependency-name: Microsoft.Extensions.Caching.Memory dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 102e31391..cd49fc752 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -67,7 +67,7 @@ - + From ad214e098a1446302564abd0d798f1c0403e4f6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Aug 2023 03:36:23 +0000 Subject: [PATCH 22/38] Bump NBitcoin.Altcoins from 3.0.17 to 3.0.19 in /src/Miningcore Bumps [NBitcoin.Altcoins](https://github.com/MetacoSA/NBitcoin) from 3.0.17 to 3.0.19. - [Commits](https://github.com/MetacoSA/NBitcoin/compare/NBitcoin.Altcoins/v3.0.17...NBitcoin.Altcoins/v3.0.19) --- updated-dependencies: - dependency-name: NBitcoin.Altcoins dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 102e31391..8f30437e7 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -71,7 +71,7 @@ - + From 4babfcbb698a3df693642f7751b014e15dd9adb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20CRISPIN?= Date: Sat, 26 Aug 2023 03:44:23 +0000 Subject: [PATCH 23/38] Update dotnet.yml --- .github/workflows/dotnet.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 5a20a8e1b..4d1565e34 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -13,13 +13,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Install Build dependencies run: sudo apt-get install -y cmake build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.x - name: Restore dependencies From c78a35c0e8289c7a5cf1cb8fe6af3538adee97f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Aug 2023 03:51:15 +0000 Subject: [PATCH 24/38] Bump AutoMapper from 12.0.0 to 12.0.1 in /src/Miningcore Bumps [AutoMapper](https://github.com/AutoMapper/AutoMapper) from 12.0.0 to 12.0.1. - [Release notes](https://github.com/AutoMapper/AutoMapper/releases) - [Changelog](https://github.com/AutoMapper/AutoMapper/blob/master/docs/API-Changes.md) - [Commits](https://github.com/AutoMapper/AutoMapper/compare/v12.0.0...v12.0.1) --- updated-dependencies: - dependency-name: AutoMapper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 77abd01c1..fd57238cb 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -59,7 +59,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + From 7d65bd6b8ba88ad3df329a9db82505661edf481a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Aug 2023 03:51:32 +0000 Subject: [PATCH 25/38] Bump FluentValidation from 11.2.2 to 11.7.1 in /src/Miningcore Bumps [FluentValidation](https://github.com/JeremySkinner/fluentvalidation) from 11.2.2 to 11.7.1. - [Release notes](https://github.com/JeremySkinner/fluentvalidation/releases) - [Changelog](https://github.com/FluentValidation/FluentValidation/blob/main/Changelog.txt) - [Commits](https://github.com/JeremySkinner/fluentvalidation/compare/11.2.2...11.7.1) --- updated-dependencies: - dependency-name: FluentValidation dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 933e9c885..f124c17ba 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -61,7 +61,7 @@ - + From 92352983605977c038cc21c29fbcf5f99fc45f3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Aug 2023 03:52:52 +0000 Subject: [PATCH 26/38] Bump Npgsql from 6.0.7 to 7.0.4 in /src/Miningcore Bumps [Npgsql](https://github.com/npgsql/npgsql) from 6.0.7 to 7.0.4. - [Release notes](https://github.com/npgsql/npgsql/releases) - [Commits](https://github.com/npgsql/npgsql/compare/v6.0.7...v7.0.4) --- updated-dependencies: - dependency-name: Npgsql dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- src/Miningcore/Miningcore.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index f124c17ba..2ff5bcacd 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -51,7 +51,7 @@ - + From f0b94e2698fb9db7fbb6c6a9800d0e5b97f42ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20CRISPIN?= Date: Sat, 26 Aug 2023 07:39:58 +0000 Subject: [PATCH 27/38] Update Miningcore.Tests.csproj --- src/Miningcore.Tests/Miningcore.Tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Miningcore.Tests/Miningcore.Tests.csproj b/src/Miningcore.Tests/Miningcore.Tests.csproj index 673ae9989..c52484606 100644 --- a/src/Miningcore.Tests/Miningcore.Tests.csproj +++ b/src/Miningcore.Tests/Miningcore.Tests.csproj @@ -37,8 +37,8 @@ - - + + From 3a32db12d107333f05ad2a199024f8dd63349f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20CRISPIN?= Date: Sat, 26 Aug 2023 07:49:03 +0000 Subject: [PATCH 28/38] Update Miningcore.csproj --- src/Miningcore/Miningcore.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index fd9c1e31f..974123e71 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -63,19 +63,19 @@ - + - + - - - + + + From 99ebe3a7fc78f378bb56f2f6799dc7613294f879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20CRISPIN?= Date: Sat, 26 Aug 2023 08:16:15 +0000 Subject: [PATCH 29/38] Update Miningcore.csproj --- src/Miningcore/Miningcore.csproj | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 974123e71..ae3a9825d 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -41,7 +41,7 @@ - + @@ -52,30 +52,30 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - - + + + + - - + + - - + + - - - + + + From d1538d87f4d60102ff2dd26cc9dbc4fa714af6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20CRISPIN?= Date: Sat, 26 Aug 2023 08:30:28 +0000 Subject: [PATCH 30/38] Update Miningcore.Tests.csproj --- src/Miningcore.Tests/Miningcore.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Miningcore.Tests/Miningcore.Tests.csproj b/src/Miningcore.Tests/Miningcore.Tests.csproj index c52484606..e87e85c14 100644 --- a/src/Miningcore.Tests/Miningcore.Tests.csproj +++ b/src/Miningcore.Tests/Miningcore.Tests.csproj @@ -37,7 +37,7 @@ - + From 95218cc64f4d638ec3637856a8bda81605cc1c85 Mon Sep 17 00:00:00 2001 From: ceedii Date: Tue, 31 Oct 2023 14:35:44 +0000 Subject: [PATCH 31/38] Add support for Alephium (ALPH) Add support for blake3 algorithm Add Nicehash support or Veruscoin (VRSC) and other optimizations Add support Litecoin (LTC) (MWEB) Multiple C++ POW library optimizations --- .github/workflows/dotnet.yml | 6 +- examples/alephium_pool.json | 135 + examples/beam_pool.json | 19 + examples/dash_pool.json | 19 + examples/dash_pool_no_polling.json | 19 + examples/digibyte_scrypt_pool.json | 19 + examples/digibyte_sha256_pool.json | 19 + examples/firo_pool.json | 23 +- examples/flo_pool.json | 19 + examples/litecoin_dash_pool.json | 19 + examples/litecoin_pool.json | 20 + examples/monero_pool.json | 19 + examples/pakcoin_pool.json | 19 + examples/ravencoin_pool.json | 19 + examples/veruscoin_pool.json | 19 + examples/zcash_pool.json | 19 + .../Api/Extensions/MiningPoolExtensions.cs | 13 +- src/Miningcore/AutofacModule.cs | 8 +- .../Alephium/AlephiumBlockTemplate.cs | 26 + .../Alephium/AlephiumClientExtensions.cs | 31 + .../Alephium/AlephiumClientFactory.cs | 45 + .../Blockchain/Alephium/AlephiumConstants.cs | 38 + .../Alephium/AlephiumExtraNonceProvider.cs | 8 + .../Blockchain/Alephium/AlephiumJob.cs | 196 + .../Blockchain/Alephium/AlephiumJobManager.cs | 716 + .../Alephium/AlephiumPayoutHandler.cs | 630 + .../Blockchain/Alephium/AlephiumPool.cs | 395 + .../Alephium/AlephiumStratumError.cs | 23 + .../Alephium/AlephiumStratumMethods.cs | 46 + .../Blockchain/Alephium/AlephiumUtils.cs | 95 + .../Alephium/AlephiumWorkerContext.cs | 30 + .../AlephiumDaemonEndpointConfigExtra.cs | 14 + .../AlephiumPaymentProcessingConfigExtra.cs | 25 + .../Configuration/AlephiumPoolConfigExtra.cs | 20 + .../Blockchain/Alephium/RPC/AlephiumClient.cs | 13536 ++++++++++++++++ .../Blockchain/Alephium/RPC/alephium.nswag | 99 + src/Miningcore/Blockchain/Beam/BeamJob.cs | 3 +- .../Blockchain/Beam/BeamJobManager.cs | 99 +- .../Blockchain/Beam/BeamPayoutHandler.cs | 8 +- src/Miningcore/Blockchain/Beam/BeamPool.cs | 24 +- .../Beam/StratumResponses/BeamJobResponse.cs | 3 + .../Blockchain/Bitcoin/BitcoinConstants.cs | 5 + .../Blockchain/Bitcoin/BitcoinJob.cs | 12 + .../Blockchain/Bitcoin/BitcoinJobManager.cs | 45 + .../Bitcoin/BitcoinJobManagerBase.cs | 10 +- .../Blockchain/Bitcoin/BitcoinUtils.cs | 12 + .../Bitcoin/DaemonResponses/Mweb.cs | 6 + .../Equihash/DaemonRequests/SendCurrency.cs | 12 + .../Blockchain/Equihash/EquihashConstants.cs | 8 + .../Blockchain/Equihash/EquihashJobManager.cs | 29 +- .../Equihash/EquihashPayoutHandler.cs | 174 +- .../Blockchain/Equihash/EquihashPool.cs | 42 +- .../Ergo/Configuration/ErgoPoolConfigExtra.cs | 2 +- .../Blockchain/Ethereum/EthereumConstants.cs | 15 + .../Ethereum/EthereumPayoutHandler.cs | 18 +- .../Blockchain/Progpow/ProgpowJob.cs | 2 +- .../Blockchain/Progpow/ProgpowJobManager.cs | 4 +- .../Blockchain/Progpow/ProgpowPool.cs | 4 +- src/Miningcore/Configuration/ClusterConfig.cs | 355 +- .../Configuration/ClusterConfigExtensions.cs | 26 +- .../Crypto/Hashing/Algorithms/Allium.cs | 21 + .../Crypto/Hashing/Algorithms/Blake3.cs | 21 + .../Crypto/Hashing/Algorithms/CpuPower.cs | 21 + .../Crypto/Hashing/Algorithms/Power2b.cs | 21 + .../Crypto/Hashing/Algorithms/Skein2.cs | 21 + .../Crypto/Hashing/Algorithms/Skydoge.cs | 21 + .../Crypto/Hashing/Algorithms/Yescrypt.cs | 21 + .../Crypto/Hashing/Algorithms/YescryptR16.cs | 21 + .../Crypto/Hashing/Algorithms/YescryptR32.cs | 21 + .../Crypto/Hashing/Algorithms/YescryptR8.cs | 21 + .../Crypto/Hashing/Algorithms/Yespower.cs | 21 + .../Crypto/Hashing/Algorithms/YespowerIC.cs | 21 + .../Crypto/Hashing/Algorithms/YespowerR16.cs | 21 + .../Crypto/Hashing/Algorithms/YespowerTIDE.cs | 21 + .../Crypto/Hashing/Ethash/Ethashb3/Cache.cs | 169 + .../Hashing/Ethash/Ethashb3/Ethashb3Light.cs | 92 + src/Miningcore/Native/EthHashB3.cs | 112 + src/Miningcore/Native/Multihash.cs | 42 + src/Miningcore/Nicehash/NicehashService.cs | 3 + .../PaymentSchemes/PPLNSPaymentScheme.cs | 4 +- .../PaymentSchemes/PROPPaymentScheme.cs | 4 +- .../PaymentSchemes/SOLOPaymentScheme.cs | 8 +- .../Postgres/Repositories/BlockRepository.cs | 16 +- .../Repositories/IBlockRepository.cs | 1 + src/Miningcore/build-libs-linux.sh | 1 + src/Miningcore/coins.json | 44 +- src/Native/libbeamhash/Makefile | 2 +- src/Native/libethhashb3/Makefile | 16 + src/Native/libethhashb3/compiler.h | 32 + src/Native/libethhashb3/data_sizes.h | 812 + src/Native/libethhashb3/dllmain.cpp | 18 + src/Native/libethhashb3/endian.h | 78 + src/Native/libethhashb3/ethash.h | 147 + src/Native/libethhashb3/exports.cpp | 98 + src/Native/libethhashb3/fnv.h | 43 + src/Native/libethhashb3/internal.c | 885 + src/Native/libethhashb3/internal.h | 224 + src/Native/libethhashb3/io.c | 119 + src/Native/libethhashb3/io.h | 202 + src/Native/libethhashb3/io_posix.c | 111 + src/Native/libethhashb3/io_win32.c | 100 + src/Native/libethhashb3/libethhashb3.sln | 31 + src/Native/libethhashb3/libethhashb3.vcxproj | 202 + src/Native/libethhashb3/mmap.h | 45 + src/Native/libethhashb3/mmap_win32.c | 84 + src/Native/libethhashb3/sha3.c | 151 + src/Native/libethhashb3/sha3.h | 31 + src/Native/libethhashb3/sha3_cryptopp.cpp | 37 + src/Native/libethhashb3/sha3_cryptopp.h | 18 + src/Native/libethhashb3/stdafx.cpp | 8 + src/Native/libethhashb3/stdafx.h | 16 + src/Native/libethhashb3/stdint.h | 259 + src/Native/libethhashb3/targetver.h | 8 + src/Native/libethhashb3/util.h | 47 + src/Native/libethhashb3/util_win32.c | 38 + src/Native/libmultihash/Makefile | 6 +- src/Native/libmultihash/allium.c | 46 + src/Native/libmultihash/allium.h | 16 + src/Native/libmultihash/blake3/blake3.c | 610 + src/Native/libmultihash/blake3/blake3.h | 58 + src/Native/libmultihash/blake3/blake3_avx2.c | 325 + .../blake3/blake3_avx2_x86-64_unix.S | 1811 +++ .../blake3/blake3_avx2_x86-64_windows_gnu.S | 1817 +++ .../blake3_avx2_x86-64_windows_msvc.asm | 1828 +++ .../libmultihash/blake3/blake3_avx512.c | 1204 ++ .../blake3/blake3_avx512_x86-64_unix.S | 2581 +++ .../blake3/blake3_avx512_x86-64_windows_gnu.S | 2615 +++ .../blake3_avx512_x86-64_windows_msvc.asm | 2634 +++ .../libmultihash/blake3/blake3_dispatch.c | 245 + src/Native/libmultihash/blake3/blake3_impl.h | 235 + src/Native/libmultihash/blake3/blake3_neon.c | 346 + .../libmultihash/blake3/blake3_portable.c | 168 + src/Native/libmultihash/blake3/blake3_sse41.c | 559 + .../blake3/blake3_sse41_x86-64_unix.S | 2024 +++ .../blake3/blake3_sse41_x86-64_windows_gnu.S | 2069 +++ .../blake3_sse41_x86-64_windows_msvc.asm | 2089 +++ src/Native/libmultihash/blake3/main.c | 166 + src/Native/libmultihash/blake3/makefile | 60 + src/Native/libmultihash/blake3/test.py | 97 + src/Native/libmultihash/exports.cpp | 77 + src/Native/libmultihash/libmultihash.vcxproj | 36 + .../libmultihash/libmultihash.vcxproj.filters | 108 + .../libmultihash/minotaur/crypto/sha256.c | 4 +- .../libmultihash/minotaur/crypto/sha256.h | 24 +- .../libmultihash/minotaur/crypto/yespower.c | 40 +- .../libmultihash/minotaur/crypto/yespower.h | 48 +- src/Native/libmultihash/minotaur/minotaurx.c | 4 +- src/Native/libmultihash/skein2.c | 24 + src/Native/libmultihash/skein2.h | 17 + src/Native/libmultihash/skydoge.c | 133 + src/Native/libmultihash/skydoge.h | 16 + src/Native/libmultihash/yescrypt/sha256.c | 411 + src/Native/libmultihash/yescrypt/sha256.h | 62 + src/Native/libmultihash/yescrypt/sysendian.h | 124 + .../libmultihash/yescrypt/yescrypt-opt.c | 973 ++ .../libmultihash/yescrypt/yescrypt-platform.c | 187 + src/Native/libmultihash/yescrypt/yescrypt.c | 371 + src/Native/libmultihash/yescrypt/yescrypt.h | 375 + .../libmultihash/yespower/crypto/blake2b-yp.c | 322 + .../libmultihash/yespower/crypto/blake2b-yp.h | 42 + .../libmultihash/yespower/crypto/sph_types.h | 1976 +++ .../libmultihash/yespower/insecure_memzero.h | 1 + src/Native/libmultihash/yespower/sha256.h | 129 + src/Native/libmultihash/yespower/sysendian.h | 94 + .../libmultihash/yespower/yespower-blake2b.c | 1207 ++ .../libmultihash/yespower/yespower-combined.c | 1314 ++ .../libmultihash/yespower/yespower-platform.c | 109 + src/Native/libmultihash/yespower/yespower.h | 152 + 168 files changed, 53616 insertions(+), 349 deletions(-) create mode 100644 examples/alephium_pool.json create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumBlockTemplate.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumClientExtensions.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumClientFactory.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumExtraNonceProvider.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumJob.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumPayoutHandler.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumPool.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumStratumError.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumStratumMethods.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumUtils.cs create mode 100644 src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs create mode 100644 src/Miningcore/Blockchain/Alephium/Configuration/AlephiumDaemonEndpointConfigExtra.cs create mode 100644 src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs create mode 100644 src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPoolConfigExtra.cs create mode 100644 src/Miningcore/Blockchain/Alephium/RPC/AlephiumClient.cs create mode 100644 src/Miningcore/Blockchain/Alephium/RPC/alephium.nswag create mode 100644 src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Mweb.cs create mode 100644 src/Miningcore/Blockchain/Equihash/DaemonRequests/SendCurrency.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Allium.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/CpuPower.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Power2b.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Skein2.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Skydoge.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Yescrypt.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/YescryptR16.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/YescryptR32.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/YescryptR8.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Yespower.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/YespowerIC.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/YespowerR16.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/YespowerTIDE.cs create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs create mode 100644 src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs create mode 100644 src/Miningcore/Native/EthHashB3.cs create mode 100644 src/Native/libethhashb3/Makefile create mode 100644 src/Native/libethhashb3/compiler.h create mode 100644 src/Native/libethhashb3/data_sizes.h create mode 100644 src/Native/libethhashb3/dllmain.cpp create mode 100644 src/Native/libethhashb3/endian.h create mode 100644 src/Native/libethhashb3/ethash.h create mode 100644 src/Native/libethhashb3/exports.cpp create mode 100644 src/Native/libethhashb3/fnv.h create mode 100644 src/Native/libethhashb3/internal.c create mode 100644 src/Native/libethhashb3/internal.h create mode 100644 src/Native/libethhashb3/io.c create mode 100644 src/Native/libethhashb3/io.h create mode 100644 src/Native/libethhashb3/io_posix.c create mode 100644 src/Native/libethhashb3/io_win32.c create mode 100644 src/Native/libethhashb3/libethhashb3.sln create mode 100644 src/Native/libethhashb3/libethhashb3.vcxproj create mode 100644 src/Native/libethhashb3/mmap.h create mode 100644 src/Native/libethhashb3/mmap_win32.c create mode 100644 src/Native/libethhashb3/sha3.c create mode 100644 src/Native/libethhashb3/sha3.h create mode 100644 src/Native/libethhashb3/sha3_cryptopp.cpp create mode 100644 src/Native/libethhashb3/sha3_cryptopp.h create mode 100644 src/Native/libethhashb3/stdafx.cpp create mode 100644 src/Native/libethhashb3/stdafx.h create mode 100644 src/Native/libethhashb3/stdint.h create mode 100644 src/Native/libethhashb3/targetver.h create mode 100644 src/Native/libethhashb3/util.h create mode 100644 src/Native/libethhashb3/util_win32.c create mode 100644 src/Native/libmultihash/allium.c create mode 100644 src/Native/libmultihash/allium.h create mode 100644 src/Native/libmultihash/blake3/blake3.c create mode 100644 src/Native/libmultihash/blake3/blake3.h create mode 100644 src/Native/libmultihash/blake3/blake3_avx2.c create mode 100644 src/Native/libmultihash/blake3/blake3_avx2_x86-64_unix.S create mode 100644 src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_gnu.S create mode 100644 src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_msvc.asm create mode 100644 src/Native/libmultihash/blake3/blake3_avx512.c create mode 100644 src/Native/libmultihash/blake3/blake3_avx512_x86-64_unix.S create mode 100644 src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_gnu.S create mode 100644 src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_msvc.asm create mode 100644 src/Native/libmultihash/blake3/blake3_dispatch.c create mode 100644 src/Native/libmultihash/blake3/blake3_impl.h create mode 100644 src/Native/libmultihash/blake3/blake3_neon.c create mode 100644 src/Native/libmultihash/blake3/blake3_portable.c create mode 100644 src/Native/libmultihash/blake3/blake3_sse41.c create mode 100644 src/Native/libmultihash/blake3/blake3_sse41_x86-64_unix.S create mode 100644 src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_gnu.S create mode 100644 src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_msvc.asm create mode 100644 src/Native/libmultihash/blake3/main.c create mode 100644 src/Native/libmultihash/blake3/makefile create mode 100644 src/Native/libmultihash/blake3/test.py create mode 100644 src/Native/libmultihash/skein2.c create mode 100644 src/Native/libmultihash/skein2.h create mode 100644 src/Native/libmultihash/skydoge.c create mode 100644 src/Native/libmultihash/skydoge.h create mode 100644 src/Native/libmultihash/yescrypt/sha256.c create mode 100644 src/Native/libmultihash/yescrypt/sha256.h create mode 100644 src/Native/libmultihash/yescrypt/sysendian.h create mode 100644 src/Native/libmultihash/yescrypt/yescrypt-opt.c create mode 100644 src/Native/libmultihash/yescrypt/yescrypt-platform.c create mode 100644 src/Native/libmultihash/yescrypt/yescrypt.c create mode 100644 src/Native/libmultihash/yescrypt/yescrypt.h create mode 100644 src/Native/libmultihash/yespower/crypto/blake2b-yp.c create mode 100644 src/Native/libmultihash/yespower/crypto/blake2b-yp.h create mode 100644 src/Native/libmultihash/yespower/crypto/sph_types.h create mode 100644 src/Native/libmultihash/yespower/insecure_memzero.h create mode 100644 src/Native/libmultihash/yespower/sha256.h create mode 100644 src/Native/libmultihash/yespower/sysendian.h create mode 100644 src/Native/libmultihash/yespower/yespower-blake2b.c create mode 100644 src/Native/libmultihash/yespower/yespower-combined.c create mode 100644 src/Native/libmultihash/yespower/yespower-platform.c create mode 100644 src/Native/libmultihash/yespower/yespower.h diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 4d1565e34..deee508fa 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -13,13 +13,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 0 - name: Install Build dependencies run: sudo apt-get install -y cmake build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v1 with: dotnet-version: 6.0.x - name: Restore dependencies @@ -27,4 +27,4 @@ jobs: - name: Build run: dotnet build --no-restore src - name: Test - run: dotnet test --logger:"console;verbosity=detailed" --no-build --verbosity normal src + run: dotnet test --logger:"console;verbosity=detailed" --no-build --verbosity normal src \ No newline at end of file diff --git a/examples/alephium_pool.json b/examples/alephium_pool.json new file mode 100644 index 000000000..91c7a8ad2 --- /dev/null +++ b/examples/alephium_pool.json @@ -0,0 +1,135 @@ +{ + "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": "alph1", + "enabled": true, + "coin": "alephium", + "address": "aFkp9i2yxNyRW17uX4XLDStnPoguwJ6tuL", + "rewardRecipients": [ + { + "type": "op", + "address": "aFkp9i2yxNyRW17uX4XLDStnPoguwJ6tuL", + "percentage": 1 + } + ], + "clientConnectionTimeout": 600, + "socketJobMessageBufferSize": 16384, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3094": { + "listenAddress": "0.0.0.0", + "difficulty": 4, + "varDiff": { + "minDiff": 2, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 100, + "maxDelta": 512 + } + }, + "3095": { + "listenAddress": "0.0.0.0", + "difficulty": 4, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 2, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 100, + "maxDelta": 512 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 12973, + "user": null, + "password": null, + "apiKey": "", + "minerApiPort": 10973 + } + ], + "paymentProcessing": { + "enabled": true, + "walletName": "", + "walletPassword": "", + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} diff --git a/examples/beam_pool.json b/examples/beam_pool.json index 0302f1108..b55bc7673 100644 --- a/examples/beam_pool.json +++ b/examples/beam_pool.json @@ -43,6 +43,25 @@ "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": "beam1", "enabled": true, diff --git a/examples/dash_pool.json b/examples/dash_pool.json index 40d190f0c..e2ecce0d1 100644 --- a/examples/dash_pool.json +++ b/examples/dash_pool.json @@ -43,6 +43,25 @@ "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": "dash1", "enabled": true, diff --git a/examples/dash_pool_no_polling.json b/examples/dash_pool_no_polling.json index 0fb7f261c..acbc8cd13 100644 --- a/examples/dash_pool_no_polling.json +++ b/examples/dash_pool_no_polling.json @@ -43,6 +43,25 @@ "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": "dash1", "enabled": true, diff --git a/examples/digibyte_scrypt_pool.json b/examples/digibyte_scrypt_pool.json index 9e1a3960f..95b60db60 100644 --- a/examples/digibyte_scrypt_pool.json +++ b/examples/digibyte_scrypt_pool.json @@ -43,6 +43,25 @@ "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": "dgb-scrypt-1", "enabled": true, diff --git a/examples/digibyte_sha256_pool.json b/examples/digibyte_sha256_pool.json index 98ffff216..10c54d4c5 100644 --- a/examples/digibyte_sha256_pool.json +++ b/examples/digibyte_sha256_pool.json @@ -43,6 +43,25 @@ "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": "dgb-sha256-1", "enabled": true, diff --git a/examples/firo_pool.json b/examples/firo_pool.json index e67494aa6..dbc414cec 100644 --- a/examples/firo_pool.json +++ b/examples/firo_pool.json @@ -43,6 +43,25 @@ "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": "firo1", "enabled": true, @@ -65,7 +84,6 @@ "percentage": 1 } ], - "hasBrokenSendMany": true, "blockRefreshInterval": 0, "jobRebroadcastTimeout": 0, "clientConnectionTimeout": 600, @@ -120,8 +138,7 @@ "payoutScheme": "PPLNS", "payoutSchemeConfig": { "factor": 0.5 - }, - "minersPayTxFees": true + } } }] } diff --git a/examples/flo_pool.json b/examples/flo_pool.json index 9b9082ac5..3dff7339b 100644 --- a/examples/flo_pool.json +++ b/examples/flo_pool.json @@ -43,6 +43,25 @@ "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": "flo1", diff --git a/examples/litecoin_dash_pool.json b/examples/litecoin_dash_pool.json index c1acc3ec1..f545c0d2d 100644 --- a/examples/litecoin_dash_pool.json +++ b/examples/litecoin_dash_pool.json @@ -43,6 +43,25 @@ "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": "ltc1", "enabled": true, diff --git a/examples/litecoin_pool.json b/examples/litecoin_pool.json index f7e43f86f..f386b9f8a 100644 --- a/examples/litecoin_pool.json +++ b/examples/litecoin_pool.json @@ -43,10 +43,30 @@ "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": "ltc1", "enabled": true, "coin": "litecoin", + "addressType": "litecoin", "address": "LNDA11u4HWzbJaBGiHDvs6SmA8M6avB3wH", "rewardRecipients": [ { diff --git a/examples/monero_pool.json b/examples/monero_pool.json index dceda5051..01c3b0d7a 100644 --- a/examples/monero_pool.json +++ b/examples/monero_pool.json @@ -43,6 +43,25 @@ "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": "xmr1", "enabled": true, diff --git a/examples/pakcoin_pool.json b/examples/pakcoin_pool.json index 4ca78a997..a105f31bf 100644 --- a/examples/pakcoin_pool.json +++ b/examples/pakcoin_pool.json @@ -43,6 +43,25 @@ "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": "pak1", "enabled": true, diff --git a/examples/ravencoin_pool.json b/examples/ravencoin_pool.json index 91101623c..435beacfb 100644 --- a/examples/ravencoin_pool.json +++ b/examples/ravencoin_pool.json @@ -43,6 +43,25 @@ "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": "rvn1", "enabled": true, diff --git a/examples/veruscoin_pool.json b/examples/veruscoin_pool.json index 89ae7b702..295a2e142 100644 --- a/examples/veruscoin_pool.json +++ b/examples/veruscoin_pool.json @@ -43,6 +43,25 @@ "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": "vrsc1", "enabled": true, diff --git a/examples/zcash_pool.json b/examples/zcash_pool.json index dfbd848b7..623b8b745 100644 --- a/examples/zcash_pool.json +++ b/examples/zcash_pool.json @@ -44,6 +44,25 @@ "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": "zec1", "enabled": true, diff --git a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs index d3c46939c..dd5e19187 100644 --- a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs +++ b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs @@ -1,6 +1,7 @@ using AutoMapper; using Miningcore.Api.Responses; using Miningcore.Blockchain; +using Miningcore.Blockchain.Alephium.Configuration; using Miningcore.Blockchain.Ergo.Configuration; using Miningcore.Configuration; using Miningcore.Extensions; @@ -29,8 +30,16 @@ public static PoolInfo ToPoolInfo(this PoolConfig poolConfig, IMapper mapper, Pe if(poolInfo.PaymentProcessing.Extra != null) { var extra = poolInfo.PaymentProcessing.Extra; - - extra.StripValue(nameof(ErgoPaymentProcessingConfigExtra.WalletPassword)); + + switch(poolInfo.Coin.Family) + { + case "alephium": + extra.StripValue(nameof(AlephiumPaymentProcessingConfigExtra.WalletPassword)); + break; + case "ergo": + extra.StripValue(nameof(ErgoPaymentProcessingConfigExtra.WalletPassword)); + break; + } } if(poolInfo.Ports != null) diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index 6348fd620..d105ffcec 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -2,11 +2,13 @@ using Autofac; using Miningcore.Api; using Miningcore.Banning; +using Miningcore.Blockchain.Alephium; using Miningcore.Blockchain.Beam; using Miningcore.Blockchain.Bitcoin; using Miningcore.Blockchain.Conceal; using Miningcore.Blockchain.Cryptonote; using Miningcore.Blockchain.Equihash; +using Miningcore.Blockchain.Ergo; using Miningcore.Blockchain.Ethereum; using Miningcore.Blockchain.Progpow; using Miningcore.Configuration; @@ -25,7 +27,6 @@ using Module = Autofac.Module; using Microsoft.AspNetCore.Mvc; using Microsoft.IO; -using Miningcore.Blockchain.Ergo; using Miningcore.Nicehash; using Miningcore.Pushover; @@ -160,6 +161,11 @@ protected override void Load(ContainerBuilder builder) .Keyed(PayoutScheme.PROP) .SingleInstance(); + ////////////////////// + // Alephium + + builder.RegisterType(); + ////////////////////// // Beam diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumBlockTemplate.cs b/src/Miningcore/Blockchain/Alephium/AlephiumBlockTemplate.cs new file mode 100644 index 000000000..b416a2ea1 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumBlockTemplate.cs @@ -0,0 +1,26 @@ +using System.Numerics; +using Miningcore.Serialization; +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Alephium; + +public class AlephiumBlockTemplate +{ + public string JobId { get; set; } = null; + + public ulong Height { get; set; } + + public DateTime Timestamp { get; set; } + + public int FromGroup { get; set; } = 0; + + public int ToGroup { get; set; } = 3; + + public string HeaderBlob { get; set; } + + public string TxsBlob { get; set; } + + public string TargetBlob { get; set; } + + public int ChainIndex { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumClientExtensions.cs b/src/Miningcore/Blockchain/Alephium/AlephiumClientExtensions.cs new file mode 100644 index 000000000..f827b650a --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumClientExtensions.cs @@ -0,0 +1,31 @@ +using System.Text; + +namespace Miningcore.Blockchain.Alephium; + +public partial class AlephiumClient +{ + public Dictionary RequestHeaders { get; } = new(); + + private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, StringBuilder url, CancellationToken ct) + { + foreach(var pair in RequestHeaders) + request.Headers.Add(pair.Key, pair.Value); + + return Task.CompletedTask; + } + + private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, String url, CancellationToken ct) + { + return Task.CompletedTask; + } + + private Task PrepareRequestAsync(HttpClient client, HttpRequestMessage request, string url) + { + return Task.CompletedTask; + } + + private static Task ProcessResponseAsync(HttpClient client, HttpResponseMessage response, CancellationToken ct) + { + return Task.CompletedTask; + } +} diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumClientFactory.cs b/src/Miningcore/Blockchain/Alephium/AlephiumClientFactory.cs new file mode 100644 index 000000000..ab30c8aff --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumClientFactory.cs @@ -0,0 +1,45 @@ +using System.Net; +using System.Net.Http.Headers; +using Miningcore.Blockchain.Alephium.Configuration; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Mining; +using NLog; + +namespace Miningcore.Blockchain.Alephium; + +public static class AlephiumClientFactory +{ + public static AlephiumClient CreateClient(PoolConfig poolConfig, ClusterConfig clusterConfig, ILogger logger) + { + var epConfig = poolConfig.Daemons.First(); + var extra = epConfig.Extra.SafeExtensionDataAs(); + + if(logger != null && clusterConfig.PaymentProcessing?.Enabled == true && + poolConfig.PaymentProcessing?.Enabled == true && string.IsNullOrEmpty(extra?.ApiKey)) + throw new PoolStartupException("Alephium daemon apiKey not provided", poolConfig.Id); + + var baseUrl = new UriBuilder(epConfig.Ssl || epConfig.Http2 ? Uri.UriSchemeHttps : Uri.UriSchemeHttp, + epConfig.Host, epConfig.Port, epConfig.HttpPath); + + var result = new AlephiumClient(baseUrl.ToString(), new HttpClient(new HttpClientHandler + { + AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, + + ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true, + })); + + if(!string.IsNullOrEmpty(extra?.ApiKey)) + result.RequestHeaders["X-API-KEY"] = extra.ApiKey; + + if(!string.IsNullOrEmpty(epConfig.User)) + { + var auth = $"{epConfig.User}:{epConfig.Password}"; + result.RequestHeaders["Authorization"] = new AuthenticationHeaderValue("Basic", auth.ToByteArrayBase64()).ToString(); + } +#if DEBUG + result.ReadResponseAsString = true; +#endif + return result; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs b/src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs new file mode 100644 index 000000000..6af843268 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumConstants.cs @@ -0,0 +1,38 @@ +using System.Globalization; +using System.Numerics; +using System.Text.RegularExpressions; +using Miningcore.Util; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Blockchain.Alephium; + +public static class AlephiumConstants +{ + public const int Diff1TargetNumZero = 30; + public static BigInteger Diff1Target = BigInteger.Pow(2, 256 - Diff1TargetNumZero) - 1; + public static readonly double Pow2xDiff1TargetNumZero = Math.Pow(2, Diff1TargetNumZero); + public static int GroupSize = 4; + public static int NonceLength = 24; + public static int NumZeroAtLeastInHash = 37; + public static int HashLength = 32; + public const uint ShareMultiplier = 1; + // ALPH smallest unit is called PHI: https://wiki.alephium.org/glossary#gas-price + public const decimal SmallestUnit = 1000000000000000000; + + // Socket miner API + public const int MessageHeaderSize = 4; // 4 bytes body length + public const byte JobsMessageType = 0x00; + public const byte SubmitResultMessageType = 0x01; + public const byte SubmitBlockMessageType = 0x00; + + // Gas (Transaction) + public const decimal UtxoConsolidationNodeReleaseVersion = 230; + public const decimal DefaultGasPrice = 100000000000; + public const int TxBaseGas = 1000; + public const int MinGasPerTx = 20000; + public const int MaxGasPerTx = 625000; + public const int GasPerInput = 2000; + public const int GasPerOutput = 4500; + public const int P2pkUnlockGas = 2060; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumExtraNonceProvider.cs b/src/Miningcore/Blockchain/Alephium/AlephiumExtraNonceProvider.cs new file mode 100644 index 000000000..d4268ff5d --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumExtraNonceProvider.cs @@ -0,0 +1,8 @@ +namespace Miningcore.Blockchain.Alephium; + +public class AlephiumExtraNonceProvider : ExtraNonceProviderBase +{ + public AlephiumExtraNonceProvider(string poolId, int size, byte? clusterInstanceId) : base(poolId, size, clusterInstanceId) + { + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumJob.cs b/src/Miningcore/Blockchain/Alephium/AlephiumJob.cs new file mode 100644 index 000000000..b5ec12bc1 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumJob.cs @@ -0,0 +1,196 @@ +using System.Globalization; +using System.Numerics; +using System.Collections.Concurrent; +using System.Text; +using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using NBitcoin; + +namespace Miningcore.Blockchain.Alephium; + +public class AlephiumJobParams +{ + public string JobId { get; init; } + public int FromGroup { get; init; } + public int ToGroup { get; init; } + public string HeaderBlob { get; init; } + public string TxsBlob { get; init; } + public string TargetBlob { get; set; } +} + +public class AlephiumJob +{ + protected IMasterClock clock; + public AlephiumBlockTemplate BlockTemplate { get; private set; } + public double Difficulty { get; private set; } + public string JobId { get; protected set; } + protected uint256 blockTargetValue; + + private AlephiumJobParams jobParams; + private readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); + private static readonly IHashAlgorithm hasher = new Blake3(); + + private static byte[] GetBigEndianUInt32(uint value) + { + byte[] bytes = new byte[4]; + + bytes[0] = (byte)((value >> 24) & 0xFF); + bytes[1] = (byte)((value >> 16) & 0xFF); + bytes[2] = (byte)((value >> 8) & 0xFF); + bytes[3] = (byte)(value & 0xFF); + + return bytes; + } + + protected bool RegisterSubmit(string nonce) + { + var key = new StringBuilder() + .Append(nonce) + .ToString(); + + return submissions.TryAdd(key, true); + } + + public virtual byte[] SerializeCoinbase(string nonce) + { + 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) + + using(var stream = new MemoryStream()) + { + stream.Write(GetBigEndianUInt32(messageSize)); + stream.WriteByte(AlephiumConstants.SubmitBlockMessageType); + stream.Write(GetBigEndianUInt32(blockSize)); + stream.Write(nonceBytes); + stream.Write(headerBlobBytes); + stream.Write(txsBlobBytes); + + return stream.ToArray(); + } + } + + protected virtual Share ProcessShareInternal(StratumConnection worker, string nonce) + { + var context = worker.ContextAs(); + + var nonceBytes = (Span) nonce.HexToByteArray(); + + // validate nonce + if(nonceBytes.Length != AlephiumConstants.NonceLength) + throw new AlephiumStratumException(AlephiumStratumError.InvalidNonce, "incorrect size of nonce"); + + var headerBytes = (Span) BlockTemplate.HeaderBlob.HexToByteArray(); + + // concat nonce and header + Span headerNonceBytes = stackalloc byte[nonceBytes.Length + headerBytes.Length]; + nonceBytes.CopyTo(headerNonceBytes); + + headerBytes.CopyTo(headerNonceBytes[nonceBytes.Length..]); + + // I know, the following looks weird but it's Alephium blockHash calculation method: https://wiki.alephium.org/mining/integration/#calculating-the-blockhash + Span tmpHashBytes = stackalloc byte[32]; + hasher.Digest(headerNonceBytes, tmpHashBytes); + Span hashBytes = stackalloc byte[32]; + hasher.Digest(tmpHashBytes, hashBytes); + + var (fromGroup, toGroup) = AlephiumUtils.BlockChainIndex(hashBytes); + // validate blockchainIndex + if (fromGroup != BlockTemplate.FromGroup || toGroup != BlockTemplate.ToGroup) + throw new AlephiumStratumException(AlephiumStratumError.InvalidBlockChainIndex, $"invalid block chain index, expected: ['fromGroup': {BlockTemplate.FromGroup}, 'toGroup': {BlockTemplate.ToGroup}], received['fromGroup': {fromGroup}, 'toGroup': {toGroup}]"); + + var targetHashBytes = new Target(new BigInteger(hashBytes, true, true)); + var hashBytesValue = targetHashBytes.ToUInt256(); + + // calc share-diff + var shareDiff = (double) new BigRational(AlephiumConstants.Diff1Target * 1024, targetHashBytes.ToBigInteger()) / 1024; + // diff check + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = hashBytesValue <= 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 AlephiumStratumException(AlephiumStratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new AlephiumStratumException(AlephiumStratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var result = new Share + { + BlockHeight = (long) BlockTemplate.Height, + NetworkDifficulty = Difficulty, + Difficulty = stratumDifficulty / AlephiumConstants.ShareMultiplier + }; + + if(isBlockCandidate) + { + result.IsBlockCandidate = true; + result.BlockHash = hashBytes.ToHexString(); + } + + return result; + } + + public AlephiumJobParams GetJobParams() + { + return jobParams; + } + + public virtual Share ProcessShare(StratumConnection worker, string nonce) + { + Contract.RequiresNonNull(worker); + Contract.Requires(!string.IsNullOrEmpty(nonce)); + + var context = worker.ContextAs(); + + // dupe check + if(!RegisterSubmit(nonce)) + throw new AlephiumStratumException(AlephiumStratumError.DuplicatedShare, $"duplicate share"); + + return ProcessShareInternal(worker, nonce); + } + + public void Init(AlephiumBlockTemplate blockTemplate) + { + Contract.RequiresNonNull(blockTemplate); + + JobId = blockTemplate.JobId; + var target = new Target(blockTemplate.TargetBlob.HexToReverseByteArray().AsSpan().ToBigInteger()); + Difficulty = (double) new BigRational(AlephiumConstants.Diff1Target * 1024, target.ToBigInteger() * 1024) * AlephiumConstants.Pow2xDiff1TargetNumZero; + blockTargetValue = target.ToUInt256(); + BlockTemplate = blockTemplate; + + jobParams = new AlephiumJobParams + { + JobId = JobId, + FromGroup = BlockTemplate.FromGroup, + ToGroup = BlockTemplate.ToGroup, + HeaderBlob = BlockTemplate.HeaderBlob, + TxsBlob = string.Empty, + TargetBlob = string.Empty, + }; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs b/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs new file mode 100644 index 000000000..3fc6438c4 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs @@ -0,0 +1,716 @@ +using System; +using static System.Array; +using System.Globalization; +using System.Numerics; +using System.Reactive; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Security.Cryptography; +using System.Text; +using System.IO; +using System.Net; +using System.Net.Sockets; +using Autofac; +using Miningcore.Blockchain.Alephium.Configuration; +using NLog; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Notifications.Messages; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Alephium; + +public class AlephiumJobManager : JobManagerBase +{ + public AlephiumJobManager( + IComponentContext ctx, + IMessageBus messageBus, + IMasterClock clock, + IExtraNonceProvider extraNonceProvider) : + base(ctx, messageBus) + { + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(extraNonceProvider); + + this.clock = clock; + this.extraNonceProvider = extraNonceProvider; + } + + private DaemonEndpointConfig[] daemonEndpoints; + 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; + + protected IObservable AlephiumSubscribeStratumApiSocketClient(CancellationToken ct, DaemonEndpointConfig endPoint, + AlephiumDaemonEndpointConfigExtra extraDaemonEndpoint, object payload = null, + JsonSerializerSettings payloadJsonSerializerSettings = null) + { + return Observable.Defer(() => Observable.Create(obs => + { + var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); + + Task.Run(async () => + { + using(cts) + { + retry: + byte[] receiveBuffer = new byte[socketJobMessageBufferSize]; + + try + { + int port = extraDaemonEndpoint.MinerApiPort; + IPAddress[] iPAddress = await Dns.GetHostAddressesAsync(endPoint.Host, AddressFamily.InterNetwork, cts.Token); + IPEndPoint ipEndPoint = new IPEndPoint(iPAddress.First(), port); + using Socket client = new(SocketType.Stream, ProtocolType.Tcp); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + logger.Debug(() => $"Establishing socket connection with `{iPAddress.First().ToString()}:{port}`"); + await client.ConnectAsync(ipEndPoint, cts.Token); + if (client.Connected) + logger.Debug(() => $"Socket connection succesffuly established"); + + using NetworkStream stream = new NetworkStream(client, false); + string hello = "hello"; + byte[] requestData = Encoding.UTF8.GetBytes($"{hello}\r\n"); + int receivedBytes; + + // Message + byte messageType; + int startOffset; + byte[] message; + + MemoryStream memory; + BinaryReader reader; + + // Job + //int offset; + AlephiumBlockTemplate[] alephiumBlockTemplate; + uint jobSize; + int fromGroup; + int toGroup; + uint headerBlobLength; + byte[] headerBlob; + uint txsBlobLength; + byte[] txsBlob; + uint targetLength; + byte[] targetBlob; + + ChainInfo chainInfo; + + + logger.Debug(() => $"Sending request `{hello}`"); + // send + await stream.WriteAsync(requestData, 0, requestData.Length, cts.Token); + + logger.Debug(() => $"Waiting for data"); + // receive + while(!cts.IsCancellationRequested && (receivedBytes = await stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, cts.Token)) != 0) + { + logger.Debug(() => $"{receivedBytes} byte(s) of data have been received - current buffer size [{receiveBuffer.Length}]"); + + messageType = receiveBuffer[AlephiumConstants.MessageHeaderSize]; + if (messageType == AlephiumConstants.JobsMessageType) + { + logger.Debug(() => $"Job(s) received :D"); + startOffset = AlephiumConstants.MessageHeaderSize + 1; // 1 byte message type + message = new byte[receivedBytes - startOffset]; + Buffer.BlockCopy(receiveBuffer, startOffset, message, 0, receivedBytes - startOffset); + + using (memory = new MemoryStream(message)) + { + using (reader = new BinaryReader(memory)) + { + jobSize = ReadBigEndianUInt32(reader); + //logger.Debug(() => $"Parsing {jobSize} job(s)"); + + alephiumBlockTemplate = new AlephiumBlockTemplate[jobSize]; + + for (int index = 0; index < jobSize; index++) + { + logger.Debug(() => $"Job ({index + 1})"); + fromGroup = (int)ReadBigEndianUInt32(reader); + toGroup = (int)ReadBigEndianUInt32(reader); + //logger.Debug(() => $"fromGroup: {fromGroup} - toGroup: {toGroup}"); + + chainInfo = await rpc.GetBlockflowChainInfoAsync(fromGroup, toGroup, cts.Token); + //logger.Debug(() => $"Height: {chainInfo?.CurrentHeight + 1}"); + + headerBlobLength = ReadBigEndianUInt32(reader); + //logger.Debug(() => $"headerBlobLength: {headerBlobLength}"); + headerBlob = reader.ReadBytes((int)headerBlobLength); + //logger.Debug(() => $"headerBlob: {headerBlob.ToHexString()}"); + + txsBlobLength = ReadBigEndianUInt32(reader); + //logger.Debug(() => $"txsBlobLength: {txsBlobLength}"); + txsBlob = reader.ReadBytes((int)txsBlobLength); + //logger.Debug(() => $"txsBlob: {txsBlob.ToHexString()}"); + + targetLength = ReadBigEndianUInt32(reader); + //logger.Debug(() => $"targetLength: {targetLength}"); + targetBlob = reader.ReadBytes((int)targetLength); + //logger.Debug(() => $"targetBlob: {targetBlob.ToHexString()}"); + + alephiumBlockTemplate[index] = new AlephiumBlockTemplate + { + JobId = NextJobId("X"), + Height = (ulong) chainInfo?.CurrentHeight + 1, + Timestamp = clock.Now, + FromGroup = fromGroup, + ToGroup = toGroup, + HeaderBlob = headerBlob.ToHexString(), + TxsBlob = txsBlob.ToHexString(), + TargetBlob = targetBlob.ToHexString(), + ChainIndex = fromGroup * AlephiumConstants.GroupSize + toGroup, + }; + } + + // publish + //logger.Debug(() => $"Publishing..."); + obs.OnNext(alephiumBlockTemplate); + } + } + } + } + + logger.Debug(() => $"No more data received. Bye!"); + client.Shutdown(SocketShutdown.Both); + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while streaming socket responses. Reconnecting in 10s"); + } + + if(!cts.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromSeconds(10), cts.Token); + goto retry; + } + } + }, cts.Token); + + return Disposable.Create(() => { cts.Cancel(); }); + })); + } + + private uint ReadBigEndianUInt32(BinaryReader reader, int count = 4) + { + byte[] tmpByte = reader.ReadBytes(count); + Array.Reverse(tmpByte); + return BitConverter.ToUInt32(tmpByte, 0); + } + + private void SetupJobUpdates(CancellationToken ct) + { + // Prepare data for the stratum API socket + var daemonEndpoint = daemonEndpoints.First(); + var extraDaemonEndpoint = daemonEndpoint.Extra.SafeExtensionDataAs(); + + if(extraDaemonEndpoint?.MinerApiPort == null) + throw new PoolStartupException("Alephium Node's Miner API Port `minerApiPort` not provided", poolConfig.Id); + + var blockFound = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); + + var triggers = new List> + { + blockFound.Select(_ => (JobRefreshBy.BlockFound, (AlephiumBlockTemplate[]) null)) + }; + + // Listen to the stratum API socket + var getWorkSocket = AlephiumSubscribeStratumApiSocketClient(ct, daemonEndpoint, extraDaemonEndpoint) + .Publish() + .RefCount(); + + triggers.Add(getWorkSocket + .Select(blockTemplates => (JobRefreshBy.Socket, blockTemplates)) + .Publish() + .RefCount()); + + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (AlephiumBlockTemplate[]) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + + Jobs = triggers.Merge() + .Select(x => Observable.FromAsync(() => UpdateJob(ct, x.Via, x.Data))) + .Concat() + .Where(x => x) + .Do(x => + { + if(x) + hasInitialBlockTemplate = true; + }) + .Select(x => GetJobParamsForStratum()) + .Publish() + .RefCount(); + } + + private async Task UpdateJob(CancellationToken ct, string via = null, AlephiumBlockTemplate[] blockTemplates = null) + { + var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); + + return await Task.Run(() => + { + using(cts) + { + try + { + if(blockTemplates == null) + return false; + + Random randomJob = new Random(); + var blockTemplate = blockTemplates[randomJob.Next(blockTemplates.Length)]; + + //var chainInfo = await rpc.GetBlockflowChainInfoAsync(blockTemplate.FromGroup, blockTemplate.ToGroup, ct); + + var job = currentJob; + + var isNew = job == null || + !string.IsNullOrEmpty(blockTemplate.JobId) && + (job.BlockTemplate?.JobId != blockTemplate.JobId || job.BlockTemplate?.Height < blockTemplate.Height); + + if(isNew) + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); + + if(isNew) + { + job = new AlephiumJob(); + + job.Init(blockTemplate); + + lock(jobLock) + { + validJobs.Insert(0, job); + + // trim active jobs + while(validJobs.Count > maxActiveJobs) + validJobs.RemoveAt(validJobs.Count - 1); + } + + if(isNew) + { + if(via != null) + logger.Info(() => $"Detected new block {job.BlockTemplate.Height} on chain[{job.BlockTemplate.ChainIndex}] [{via}]"); + else + logger.Info(() => $"Detected new block {job.BlockTemplate.Height} on chain[{job.BlockTemplate.ChainIndex}]"); + + // update stats + if ((job.BlockTemplate.Height - 1) > BlockchainStats.BlockHeight) + { + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = job.BlockTemplate.Height - 1; + } + } + + else + { + if(via != null) + logger.Debug(() => $"Template update {job.BlockTemplate.Height} on chain[{job.BlockTemplate.ChainIndex}] [{via}]"); + else + logger.Debug(() => $"Template update {job.BlockTemplate.Height} on chain[{job.BlockTemplate.ChainIndex}]"); + } + + currentJob = job; + } + + return isNew; + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while updating new job"); + } + + return false; + } + }, cts.Token); + } + + private async Task UpdateNetworkStatsAsync(CancellationToken ct) + { + try + { + // update stats + var info = await rpc.GetInfosInterCliquePeerInfoAsync(ct); + var infoHashrate = await rpc.GetInfosCurrentHashrateAsync(null, ct); + var infoDifficulty = await rpc.GetInfosCurrentDifficultyAsync(ct); + + BlockchainStats.ConnectedPeers = info.Count; + BlockchainStats.NetworkDifficulty = (double) infoDifficulty.Difficulty; + BlockchainStats.NetworkHashrate = AlephiumUtils.TranslateApiHashrate(infoHashrate.Hashrate); + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while updating network stats"); + } + } + + private async Task ShowDaemonSyncProgressAsync(CancellationToken ct) + { + var info = await Guard(() => rpc.GetInfosSelfCliqueAsync(ct), + ex => logger.Debug(ex)); + + if(info?.SelfReady != true || info?.Synced != true) + logger.Info(() => $"Daemon is downloading headers ..."); + } + + private async Task SubmitBlockAsync(CancellationToken ct, DaemonEndpointConfig endPoint, + AlephiumDaemonEndpointConfigExtra extraDaemonEndpoint, byte[] coinbase, object payload = null, + JsonSerializerSettings payloadJsonSerializerSettings = null) + { + Contract.RequiresNonNull(coinbase); + + bool succeed = false; + byte[] receiveBuffer = new byte[8192]; + + try + { + int port = extraDaemonEndpoint.MinerApiPort; + IPAddress[] iPAddress = await Dns.GetHostAddressesAsync(endPoint.Host, AddressFamily.InterNetwork, ct); + IPEndPoint ipEndPoint = new IPEndPoint(iPAddress.First(), port); + using Socket client = new(SocketType.Stream, ProtocolType.Tcp); + //client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1); + client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); + logger.Debug(() => $"Establishing socket connection with `{iPAddress.First().ToString()}:{port}`"); + await client.ConnectAsync(ipEndPoint, ct); + if (client.Connected) + logger.Debug(() => $"[Submitting block] - Socket connection succesffuly established"); + + using NetworkStream stream = new NetworkStream(client, false); + int receivedBytes; + + // Message + byte messageType; + int startOffset; + byte[] message; + + logger.Debug(() => $"[Submit Block] - Submitting coinbase"); + // send + await stream.WriteAsync(coinbase, 0, coinbase.Length, ct); + + // receive + while(!ct.IsCancellationRequested && (receivedBytes = await stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, ct)) != 0) + { + logger.Debug(() => $"{receivedBytes} byte(s) of data have been received"); + + messageType = receiveBuffer[AlephiumConstants.MessageHeaderSize]; + if (messageType == AlephiumConstants.SubmitResultMessageType) + { + logger.Debug(() => $"[Submit Block] - Response received :D"); + startOffset = AlephiumConstants.MessageHeaderSize + 1; // 1 byte message type + message = new byte[receivedBytes - startOffset]; + Buffer.BlockCopy(receiveBuffer, startOffset, message, 0, receivedBytes - startOffset); + + succeed = (message[8] == 1); + break; + } + } + + client.Shutdown(SocketShutdown.Both); + } + + catch(Exception) + { + // We lost that battle + messageBus.SendMessage(new AdminNotification("Block submission failed", $"Pool {poolConfig.Id} failed to submit block")); + } + + return succeed; + } + + #region API-Surface + + public IObservable Jobs { get; private set; } + public BlockchainStats BlockchainStats { get; } = new(); + public string Network => network; + + public AlephiumCoinTemplate Coin => coin; + + 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, + }; + + return responseData; + } + + public async ValueTask SubmitShareAsync(StratumConnection worker, AlephiumWorkerSubmitParams submitParams, CancellationToken ct) + { + Contract.RequiresNonNull(worker); + Contract.RequiresNonNull(submitParams); + + var context = worker.ContextAs(); + + var jobId = submitParams.JobId; + var nonce = submitParams.Nonce; + + AlephiumJob job; + + lock(jobLock) + { + job = validJobs.FirstOrDefault(x => x.JobId == jobId); + } + + if(job == null) + throw new AlephiumStratumException(AlephiumStratumError.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}]"); + + // Prepare data for the stratum API socket + var daemonEndpoint = daemonEndpoints.First(); + var extraDaemonEndpoint = daemonEndpoint.Extra.SafeExtensionDataAs(); + var jobCoinbase = job.SerializeCoinbase(nonce); + + var acceptResponse = await SubmitBlockAsync(ct, daemonEndpoint, + extraDaemonEndpoint, jobCoinbase); + + // 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 ValidateAddress(string address, CancellationToken ct) + { + if(string.IsNullOrEmpty(address)) + return false; + + var validity = await Guard(() => rpc.GetAddressesAddressGroupAsync(address, ct), + ex => logger.Debug(ex)); + + return validity?.Group1 >= 0; + } + + #endregion // API-Surface + + #region Overrides + + 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); + + // Payment-processing setup + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // validate pool wallet name + if(string.IsNullOrEmpty(extraPoolPaymentProcessingConfig.WalletName)) + throw new PoolStartupException($"Pool payment wallet name is not configured", poolConfig.Id); + + // check configured pool wallet name belongs to wallet + var validityWalletName = await Guard(() => rpc.NameAsync(extraPoolPaymentProcessingConfig.WalletName, ct), + ex=> throw new PoolStartupException($"Error validating pool payment wallet name: {ex}", poolConfig.Id)); + + // unlocked wallet if locked + if(validityWalletName.Locked) + { + var walletPassword = extraPoolPaymentProcessingConfig.WalletPassword ?? string.Empty; + + await Guard(() => rpc.NameUnlockAsync(extraPoolPaymentProcessingConfig.WalletName, new WalletUnlock {Password = walletPassword}, ct), + ex=> throw new PoolStartupException($"Error validating pool payment wallet name: {ex}", poolConfig.Id)); + + logger.Info(() => $"Pool payment wallet is unlocked"); + } + + // check configured pool wallet has 4 addresses + var validityWalletMinerAddresses = await Guard(() => rpc.NameAddressesAsync(extraPoolPaymentProcessingConfig.WalletName, ct), + ex=> throw new PoolStartupException($"Error validating pool payment wallet name: {ex}", poolConfig.Id)); + + if (validityWalletMinerAddresses?.Addresses1.Count < 4) + throw new PoolStartupException($"Pool payment wallet name: {extraPoolPaymentProcessingConfig.WalletName} must have 4 miner's addresses", poolConfig.Id); + + // check configured address belongs to wallet + var walletAddresses = await Guard(() => rpc.NameAddressesAddressAsync(extraPoolPaymentProcessingConfig.WalletName, poolConfig.Address, ct), + ex=> throw new PoolStartupException($"Pool address: {poolConfig.Address} is not controlled by pool wallet name: {extraPoolPaymentProcessingConfig.WalletName} - Error: {ex}", poolConfig.Id)); + + if(walletAddresses.Address != poolConfig.Address) + throw new PoolStartupException($"Pool address: {poolConfig.Address} is not controlled by pool wallet name: {extraPoolPaymentProcessingConfig.WalletName}", poolConfig.Id); + } + + var infosChainParams = await Guard(() => rpc.GetInfosChainParamsAsync(ct), + ex=> throw new PoolStartupException($"Daemon reports: {ex.Message}", poolConfig.Id)); + + switch(infosChainParams?.NetworkId) + { + case 0: + network = "mainnet"; + break; + case 1: + network = "testnet"; + break; + case 4: + network = "devnet"; + break; + default: + throw new PoolStartupException($"Unsupport network type '{infosChainParams?.NetworkId}'", poolConfig.Id); + } + + // update stats + BlockchainStats.NetworkType = network; + BlockchainStats.RewardType = "POW"; + + 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); + } + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + + maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 16; + socketJobMessageBufferSize = extraPoolConfig?.SocketJobMessageBufferSize ?? 131072; + + // extract standard daemon endpoints + daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .ToArray(); + + base.Configure(pc, cc); + } + + protected override void ConfigureDaemons() + { + rpc = AlephiumClientFactory.CreateClient(poolConfig, clusterConfig, logger); + } + + protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) + { + var info = await Guard(() => rpc.GetInfosSelfCliqueAsync(ct), + ex=> logger.Debug(ex)); + + if(info?.SelfReady != true || info?.Synced != true) + return false; + + return true; + } + + protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) + { + var info = await Guard(() => rpc.GetInfosInterCliquePeerInfoAsync(ct), + ex=> logger.Debug(ex)); + + return info?.Count > 0; + } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + var syncPendingNotificationShown = false; + + do + { + var work = await Guard(() => rpc.GetInfosSelfCliqueAsync(ct), + ex=> logger.Debug(ex)); + + var isSynched = (work?.SelfReady == true && work?.Synced == true); + + if(isSynched) + { + logger.Info(() => "Daemon is synced 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)); + } + + private AlephiumJobParams GetJobParamsForStratum() + { + var job = currentJob; + return job?.GetJobParams(); + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumPayoutHandler.cs b/src/Miningcore/Blockchain/Alephium/AlephiumPayoutHandler.cs new file mode 100644 index 000000000..cb5ba519f --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumPayoutHandler.cs @@ -0,0 +1,630 @@ +using System; +using Autofac; +using AutoMapper; +using Miningcore.Blockchain.Alephium.Configuration; +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.Time; +using Miningcore.Util; +using Block = Miningcore.Persistence.Model.Block; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Alephium; + +[CoinFamily(CoinFamily.Alephium)] +public class AlephiumPayoutHandler : PayoutHandlerBase, + IPayoutHandler +{ + public AlephiumPayoutHandler( + 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; + protected AlephiumClient alephiumClient; + private string network; + private AlephiumPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + + protected override string LogCategory => "Alephium 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(AlephiumPayoutHandler), pc); + + alephiumClient = AlephiumClientFactory.CreateClient(pc, cc, null); + + var infosChainParams = await Guard(() => alephiumClient.GetInfosChainParamsAsync(ct), + ex=> ReportAndRethrowApiError("Failed to get key params", ex)); + + switch(infosChainParams?.NetworkId) + { + case 0: + network = "mainnet"; + break; + case 1: + network = "testnet"; + break; + case 4: + network = "devnet"; + break; + default: + throw new PaymentException($"Unsupport network type '{infosChainParams?.NetworkId}'"); + } + } + + public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, CancellationToken ct) + { + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(blocks); + + if(blocks.Length == 0) + 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]; + + // get block info + var blockInfo = await Guard(() => alephiumClient.HashAsync((string) block.Hash, ct), + ex=> logger.Debug(ex)); + + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} contains {blockInfo.Transactions.Count} transaction(s)"); + + // get wallet miner's addresses + var walletMinersAddresses = await Guard(() => alephiumClient.GetMinersAddressesAsync(ct), + ex=> logger.Debug(ex)); + + // we only need the transaction(s) related to the block reward + var blockRewardTransactions = blockInfo.Transactions + .Where(x => x.Unsigned.Inputs.Count < 1) + .ToList(); + + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} contains {blockRewardTransactions.Count} transaction(s) related to the block reward"); + + // update real blockHeight from chain if necessary + //if (block.BlockHeight != blockInfo.Height) + //block.BlockHeight = blockInfo.Height; + + // update progress + // Two block confirmations methods are available: + // 1) ALPH default lock mechanism: All of the mined coins are locked for N minutes (up to +8 hours on mainnet, very short on testnet) + // 2) Mining pool operator provides a custom block rewards lock time, this method must be ONLY USE ON TESTNET in order to mimic MAINNET + if(extraPoolPaymentProcessingConfig?.BlockRewardsLockTime == null) + { + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} uses the default block reward lock mechanism for minimum confirmations calculation"); + + decimal transactionsLockTime = 0; + int totalTransactionsLockTime = 0; + foreach (var blockTransactionLockTime in blockRewardTransactions) + { + foreach (var unsignedLockTimeFixedOutputs in blockTransactionLockTime.Unsigned.FixedOutputs) + { + // We only need the transaction(s) for our wallet miner's addresses + if(walletMinersAddresses.Addresses.Contains(unsignedLockTimeFixedOutputs.Address)) + { + transactionsLockTime += (decimal) unsignedLockTimeFixedOutputs.LockTime; + totalTransactionsLockTime += 1; + } + } + } + if(totalTransactionsLockTime > 0) + transactionsLockTime /= totalTransactionsLockTime; + + block.ConfirmationProgress = Math.Min(1.0d, (double) ((AlephiumUtils.UnixTimeStampForApi(clock.Now) - blockInfo.Timestamp) / (transactionsLockTime - blockInfo.Timestamp))); + } + else + { + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} uses a custom [{network}] block rewards lock time: [{extraPoolPaymentProcessingConfig?.BlockRewardsLockTime}] minute(s)"); + + block.ConfirmationProgress = Math.Min(1.0d, (double) ((AlephiumUtils.UnixTimeStampForApi(clock.Now) - blockInfo.Timestamp) / ((decimal) extraPoolPaymentProcessingConfig?.BlockRewardsLockTime * 60 * 1000))); + } + + result.Add(block); + + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + var isBlockInMainChain = await Guard(() => alephiumClient.GetBlockflowIsBlockInMainChainAsync((string) block.Hash, ct), + ex=> logger.Debug(ex)); + + // We lost that battle + if(!isBlockInMainChain) + { + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} classified as orphaned because it's not the chain"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + continue; + } + + // matured and spendable? + if(block.ConfirmationProgress >= 1) + { + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + + // reset block reward + block.Reward = 0; + + foreach (var blockTransaction in blockRewardTransactions) + { + foreach (var unsignedFixedOutputs in blockTransaction.Unsigned.FixedOutputs) + { + // We only need the transaction(s) for our wallet miner's addresses + if(walletMinersAddresses.Addresses.Contains(unsignedFixedOutputs.Address)) + block.Reward += AlephiumUtils.ConvertNumberFromApi(unsignedFixedOutputs.AttoAlphAmount) / AlephiumConstants.SmallestUnit; + } + } + + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + 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(balances.Sum(x => x.Amount))} to {balances.Length} addresses"); + + // ALPH only allows multiple recipients per transaction if they belong to the same group + // So we must validate the addresses and consolidate them together in their respective group + var groupingAmounts = new List>[] + { + new List>(), + new List>(), + new List>(), + new List>(), + }; + + logger.Info(() => $"[{LogCategory}] Validating addresses..."); + foreach(var pair in amounts) + { + logger.Debug(() => $"[{LogCategory}] Address {pair.Key} with amount [{FormatAmount(pair.Value)}]"); + var validity = await Guard(() => alephiumClient.GetAddressesAddressGroupAsync(pair.Key, ct)); + + if(validity == null || !(validity?.Group1 >= 0)) + logger.Warn(()=> $"[{LogCategory}] Address {pair.Key} is not valid!"); + else + { + logger.Debug(() => $"[{LogCategory}] Address {pair.Key} belongs to group [{validity.Group1}]"); + groupingAmounts[validity.Group1].Add(pair); + } + } + + retry: + // get wallet status + var status = await alephiumClient.NameAsync(extraPoolPaymentProcessingConfig.WalletName, ct); + + // unlock wallet + if(status.Locked) + await UnlockWallet(ct); + + // get wallet addresses + var walletAddresses = await alephiumClient.NameAddressesAsync(extraPoolPaymentProcessingConfig.WalletName, ct); + if (walletAddresses?.Addresses1.Count < 4) + { + logger.Warn(() => $"[{LogCategory}] Pool payment wallet name: {extraPoolPaymentProcessingConfig.WalletName} must have 4 miner's addresses. Please fix it"); + return; + } + + // get balance + var walletBalances = await alephiumClient.NameBalancesAsync(extraPoolPaymentProcessingConfig.WalletName, ct); + var walletBalanceTotal = AlephiumUtils.ConvertNumberFromApi(walletBalances.TotalBalance) / AlephiumConstants.SmallestUnit; + var walletBalanceLocked = walletBalances.Balances1 + .Sum(x => (AlephiumUtils.ConvertNumberFromApi(x.LockedBalance) / AlephiumConstants.SmallestUnit)); + var walletBalanceAvailable = walletBalanceTotal - walletBalanceLocked; + + logger.Info(() => $"[{LogCategory}] Current wallet balance - Total: [{FormatAmount(walletBalanceTotal)}] - Locked: [{FormatAmount(walletBalanceLocked)}] - Available: [{FormatAmount(walletBalanceAvailable)}]"); + + // bail if balance does not satisfy payments + if(walletBalanceAvailable < balancesTotal) + { + logger.Warn(() => $"[{LogCategory}] Wallet balance currently short of {FormatAmount(balancesTotal - walletBalanceAvailable)}. Will try again"); + return; + } + + // check if any pool address has enough funds to cover the transaction + var anyPoolAddress = walletBalances.Balances1 + .Where(x => ((AlephiumUtils.ConvertNumberFromApi(x.Balance) / AlephiumConstants.SmallestUnit) - (AlephiumUtils.ConvertNumberFromApi(x.LockedBalance) / AlephiumConstants.SmallestUnit)) >= balancesTotal) + .FirstOrDefault(); + // No pool wallet address can cover that transaction + if(string.IsNullOrEmpty(anyPoolAddress?.Address)) + { + logger.Warn(() => $"[{LogCategory}] No pool wallet address can cover that transaction"); + + // we need to move funds between two addresses which hold the majority of coins, in order to allow payouts to resume + var wealthyPoolAddress = walletBalances.Balances1 + .OrderByDescending(x => (AlephiumUtils.ConvertNumberFromApi(x.Balance) / AlephiumConstants.SmallestUnit) - (AlephiumUtils.ConvertNumberFromApi(x.LockedBalance) / AlephiumConstants.SmallestUnit)) + .Take(2) + .ToArray(); + + // all available funds have already been moved to one address + if(((AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[1].Balance) / AlephiumConstants.SmallestUnit) - (AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[1].LockedBalance) / AlephiumConstants.SmallestUnit)) <= 0) + { + logger.Info(() => $"[{LogCategory}] All available funds have already been moved to pool wallet address {wealthyPoolAddress[0].Address} [{FormatAmount(AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[0].Balance) / AlephiumConstants.SmallestUnit)}]"); + return; + } + + logger.Info(() => $"[{LogCategory}] We will now move the funds from pool wallet address {wealthyPoolAddress[1].Address} - Total: [{FormatAmount(AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[1].Balance) / AlephiumConstants.SmallestUnit)}] - Locked: [{FormatAmount(AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[1].LockedBalance) / AlephiumConstants.SmallestUnit)}] - Available: [{FormatAmount((AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[1].Balance) / AlephiumConstants.SmallestUnit) - (AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[1].LockedBalance) / AlephiumConstants.SmallestUnit))}] - to pool wallet address {wealthyPoolAddress[0].Address} - Total: [{FormatAmount(AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[0].Balance) / AlephiumConstants.SmallestUnit)}] - Locked: [{FormatAmount(AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[0].LockedBalance) / AlephiumConstants.SmallestUnit)}] - Available: [{FormatAmount((AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[0].Balance) / AlephiumConstants.SmallestUnit) - (AlephiumUtils.ConvertNumberFromApi(wealthyPoolAddress[0].LockedBalance) / AlephiumConstants.SmallestUnit))}]"); + + var bodyChangeWealthyActiveAddress = new ChangeActiveAddress + { + Address = wealthyPoolAddress[1].Address, + }; + + await Guard(() => alephiumClient.NameChangeActiveAddressAsync(extraPoolPaymentProcessingConfig.WalletName, bodyChangeWealthyActiveAddress, ct), ex => + { + logger.Warn(() => $"[{LogCategory}] Change active address failed"); + }); + + logger.Debug(() => $"[{LogCategory}] Pool wallet address {wealthyPoolAddress[1].Address} is now the active address"); + + // get address UTXOs + var wealthyPoolAddressUtxos = await alephiumClient.GetAddressesAddressUtxosAsync(wealthyPoolAddress[1].Address, ct); + if(!string.IsNullOrEmpty(wealthyPoolAddressUtxos?.Warning)) + { + logger.Warn(() => $"[{LogCategory}] Pool wallet address: {wealthyPoolAddress[1].Address} maybe can't be used anymore: {wealthyPoolAddressUtxos.Warning}. Please fix it"); + return; + } + + logger.Debug(() => $"[{LogCategory}] Pool wallet address {wealthyPoolAddress[1].Address} has currently {wealthyPoolAddressUtxos.Utxos.Count} (locked+unlocked) UTXO(s)"); + logger.Debug(() => $"[{LogCategory}] Current Epoch Unix Timestamp {AlephiumUtils.UnixTimeStampForApi(clock.Now)} ms"); + + // create UTXOs batch + var inputWealthyUtxos = wealthyPoolAddressUtxos.Utxos + .Where(x => x.LockTime <= AlephiumUtils.UnixTimeStampForApi(clock.Now)) + .Select(x => new OutputRef + { + Hint = x.Ref.Hint, + Key = x.Ref.Key, + }) + .ToArray(); + + logger.Debug(() => $"[{LogCategory}] Pool wallet address {wealthyPoolAddress[1].Address} has currently {inputWealthyUtxos.Length} (unlocked) UTXO(s)"); + + // calculate gas amount for transaction + // ALPH Gas computation - https://wiki.alephium.org/integration/exchange#gas-computation + var inputWealthyGas = AlephiumConstants.GasPerInput * inputWealthyUtxos.Length; + var outputWealthyGas = AlephiumConstants.GasPerOutput; + var wealthyTxGas = inputWealthyGas + outputWealthyGas + AlephiumConstants.TxBaseGas + AlephiumConstants.P2pkUnlockGas + AlephiumConstants.GasPerOutput; + var wealthyEstimatedGasAmount = Math.Max(AlephiumConstants.MinGasPerTx, wealthyTxGas); + if(wealthyEstimatedGasAmount > AlephiumConstants.MaxGasPerTx) + { + logger.Warn(() => $"[{LogCategory}] Estimated necessary gas amount [{wealthyEstimatedGasAmount}] exceeds the maximum possible per transaction [{AlephiumConstants.MaxGasPerTx}]. We are in a serious pickle here"); + return; + } + + logger.Debug(() => $"[{LogCategory}] Estimated necessary gas amount: {wealthyEstimatedGasAmount}"); + + var destinationSweep = new Sweep + { + ToAddress = wealthyPoolAddress[0].Address, + GasAmount = wealthyEstimatedGasAmount, + }; + + var txSweep = await Guard(() => alephiumClient.NameSweepActiveAddressAsync(extraPoolPaymentProcessingConfig.WalletName, destinationSweep, ct), ex => + { + logger.Warn(() => $"[{LogCategory}] Sweep active address failed"); + }); + if(txSweep?.Results == null) + return; + + if(txSweep.Results.Count < 1) + logger.Warn(() => $"[{LogCategory}] Sweep transaction failed to return a transaction id"); + else + logger.Info(() => $"[{LogCategory}] Sweep transaction id: {txSweep.Results.First().TxId}"); + + goto retry; + } + + // select the pool address which has enough funds to cover the transaction + var inputAddress = walletAddresses.Addresses1 + .Where(x => x.Address == anyPoolAddress.Address) + .FirstOrDefault(); + if(string.IsNullOrEmpty(inputAddress?.Address)) + { + logger.Warn(() => $"[{LogCategory}] Pool wallet address {anyPoolAddress.Address} does not exist anymore. Please fix it"); + return; + } + + logger.Info(() => $"[{LogCategory}] Pool wallet address {inputAddress.Address} has enough funds - Total: [{FormatAmount((AlephiumUtils.ConvertNumberFromApi(anyPoolAddress.Balance) / AlephiumConstants.SmallestUnit))}] - Locked: [{FormatAmount((AlephiumUtils.ConvertNumberFromApi(anyPoolAddress.LockedBalance) / AlephiumConstants.SmallestUnit))}] - Avalaible: [{FormatAmount((AlephiumUtils.ConvertNumberFromApi(anyPoolAddress.Balance) / AlephiumConstants.SmallestUnit) - (AlephiumUtils.ConvertNumberFromApi(anyPoolAddress.LockedBalance) / AlephiumConstants.SmallestUnit))}]"); + + logger.Info(() => $"[{LogCategory}] Change active address"); + var bodyChangeActiveAddress = new ChangeActiveAddress + { + Address = inputAddress.Address, + }; + + await Guard(() => alephiumClient.NameChangeActiveAddressAsync(extraPoolPaymentProcessingConfig.WalletName, bodyChangeActiveAddress, ct), ex => + { + logger.Warn(() => $"[{LogCategory}] Change active address failed"); + }); + + logger.Debug(() => $"[{LogCategory}] Pool wallet address {inputAddress.Address} is now the active address"); + + Balance[] successBalances; + + decimal groupTotalBalance; + + Terminus[] batchDestinations; + OutputRef[] inputUtxos; + + int inputGas; + int outputGas; + int txGas; + int estimatedGasAmount; + int initialTotalAddresses; + int numberOfAddressesToRemove; + + BuildSettlement destinationsTransaction; + Sign signTxBuild; + SubmitSettlement submitTxSign; + + // Processing groups of addresses + for (var j = 0; j < groupingAmounts.Length; j++) + { + initialTotalAddresses = groupingAmounts[j].Count; + // Only groups containing addresses are processing + if(initialTotalAddresses > 0) + { + groupTotalBalance = groupingAmounts[j].Sum(x => x.Value); + logger.Info(() => $"[{LogCategory}] Processing group [{j}] containing {initialTotalAddresses} address(es), total amount [{FormatAmount(groupTotalBalance)}]"); + + logger.Info(() => $"[{LogCategory}] 1/3) Build the transaction"); + + // get address UTXOs + var inputAddressUtxos = await alephiumClient.GetAddressesAddressUtxosAsync(inputAddress.Address, ct); + if(!string.IsNullOrEmpty(inputAddressUtxos?.Warning)) + { + logger.Warn(() => $"[{LogCategory}] Pool wallet address: {anyPoolAddress.Address} maybe can't be used anymore: {inputAddressUtxos.Warning}. Please fix it"); + continue; + } + + logger.Debug(() => $"[{LogCategory}] Pool wallet address {inputAddress.Address} has currently {inputAddressUtxos.Utxos.Count} (locked+unlocked) UTXO(s)"); + logger.Debug(() => $"[{LogCategory}] Current Epoch Unix Timestamp {AlephiumUtils.UnixTimeStampForApi(clock.Now)} ms"); + + // create UTXOs batch + inputUtxos = inputAddressUtxos.Utxos + .Where(x => x.LockTime <= AlephiumUtils.UnixTimeStampForApi(clock.Now)) + .Select(x => new OutputRef + { + Hint = x.Ref.Hint, + Key = x.Ref.Key, + }) + .ToArray(); + + logger.Debug(() => $"[{LogCategory}] Pool wallet address {inputAddress.Address} has currently {inputUtxos.Length} (unlocked) UTXO(s)"); + + // calculate gas amount for transaction + // ALPH Gas computation - https://wiki.alephium.org/integration/exchange#gas-computation + inputGas = AlephiumConstants.GasPerInput * inputUtxos.Length; + outputGas = AlephiumConstants.GasPerOutput * groupingAmounts[j].Count; + txGas = inputGas + outputGas + AlephiumConstants.TxBaseGas + AlephiumConstants.P2pkUnlockGas + AlephiumConstants.GasPerOutput; + estimatedGasAmount = Math.Max(AlephiumConstants.MinGasPerTx, txGas); + if(estimatedGasAmount > AlephiumConstants.MaxGasPerTx) + { + logger.Warn(() => $"[{LogCategory}] Estimated necessary gas amount [{estimatedGasAmount}] exceeds the maximum possible per transaction [{AlephiumConstants.MaxGasPerTx}]. We need to remove addresses."); + + numberOfAddressesToRemove = (int)Math.Ceiling((decimal)(estimatedGasAmount - AlephiumConstants.MaxGasPerTx) / AlephiumConstants.GasPerOutput); + // No can do sir + if(numberOfAddressesToRemove >= initialTotalAddresses) + { + logger.Warn(() => $"[{LogCategory}] We need to remove {numberOfAddressesToRemove} address(es). But we only have {initialTotalAddresses} address(es) to pay. We are in a serious pickle here."); + continue; + } + + logger.Debug(() => $"[{LogCategory}] {numberOfAddressesToRemove} address(es) are removed"); + // trim addresses + while(groupingAmounts[j].Count > (initialTotalAddresses - numberOfAddressesToRemove)) + groupingAmounts[j].RemoveAt(groupingAmounts[j].Count - 1); + + groupTotalBalance = groupingAmounts[j].Sum(x => x.Value); + logger.Info(() => $"[{LogCategory}] Group {j} containing now {groupingAmounts[j].Count} address(es), total amount [{FormatAmount(groupTotalBalance)}]"); + + estimatedGasAmount = AlephiumConstants.MaxGasPerTx; + } + + logger.Debug(() => $"[{LogCategory}] Estimated necessary gas amount: {estimatedGasAmount} [{FormatAmount(((estimatedGasAmount * AlephiumConstants.DefaultGasPrice) / AlephiumConstants.SmallestUnit))}]"); + if(extraPoolPaymentProcessingConfig?.KeepTransactionFees == true) + logger.Debug(() => $"[{LogCategory}] Pool does not pay the transaction fee, so each address will have its payout deducted with [{FormatAmount(((estimatedGasAmount * AlephiumConstants.DefaultGasPrice) / AlephiumConstants.SmallestUnit) / groupingAmounts[j].Count)}]"); + + // create destination batch + batchDestinations = groupingAmounts[j].Select(x => new Terminus + { + Address = x.Key, + AttoAlphAmount = AlephiumUtils.ConvertNumberForApi(((extraPoolPaymentProcessingConfig?.KeepTransactionFees == false) ? x.Value * AlephiumConstants.SmallestUnit : (x.Value * AlephiumConstants.SmallestUnit) - ((estimatedGasAmount * AlephiumConstants.DefaultGasPrice) / groupingAmounts[j].Count))), + }).ToArray(); + + destinationsTransaction = new BuildSettlement + { + FromPublicKey = inputAddress.PublicKey, + Destinations = batchDestinations, + Utxos = inputUtxos, + GasAmount = estimatedGasAmount, + }; + + var txBuild = await Guard(() => alephiumClient.PostTransactionsBuildAsync(destinationsTransaction, ct), ex => + { + logger.Warn(() => $"[{LogCategory}] Build transaction failed"); + }); + if(string.IsNullOrEmpty(txBuild?.TxId)) + continue; + + logger.Debug(() => $"[{LogCategory}] Unsigned transaction {txBuild.UnsignedTx} with txId {txBuild.TxId}"); + + logger.Info(() => $"[{LogCategory}] 2/3) Sign the transaction"); + signTxBuild = new Sign + { + Data = txBuild.TxId, + }; + + var txSign = await Guard(() => alephiumClient.NameSignAsync(extraPoolPaymentProcessingConfig.WalletName, signTxBuild, ct), ex => + { + logger.Warn(() => $"[{LogCategory}] Sign transaction failed"); + }); + if(string.IsNullOrEmpty(txSign?.Signature)) + continue; + + logger.Debug(() => $"[{LogCategory}] Unsigned transaction signature {txSign.Signature}"); + + logger.Info(() => $"[{LogCategory}] 3/3) Submit signed transaction to the network"); + submitTxSign = new SubmitSettlement + { + UnsignedTx = txBuild.UnsignedTx, + Signature = txSign.Signature, + }; + + var txSubmit = await Guard(() => alephiumClient.PostTransactionsSubmitAsync(submitTxSign, ct), ex => + { + logger.Warn(() => $"[{LogCategory}] Submit signed transaction failed"); + }); + if(string.IsNullOrEmpty(txSubmit?.TxId)) + { + logger.Warn(() => $"[{LogCategory}] Payment transaction failed to return a transaction id"); + continue; + } + + // payment successful + logger.Info(() => $"[{LogCategory}] Payment transaction id: {txSubmit.TxId}"); + + successBalances = groupingAmounts[j] + .Select(x => new Balance + { + PoolId = poolConfig.Id, + Address = x.Key, + Amount = x.Value, + }) + .ToArray(); + + await PersistPaymentsAsync(successBalances, txSubmit.TxId); + + NotifyPayoutSuccess(poolConfig.Id, successBalances, new[] {txSubmit.TxId}, ((estimatedGasAmount * AlephiumConstants.DefaultGasPrice) / AlephiumConstants.SmallestUnit)); + } + } + + await LockWallet(ct); + } + + public override double AdjustShareDifficulty(double difficulty) + { + return difficulty * AlephiumConstants.Pow2xDiff1TargetNumZero; + } + + public double AdjustBlockEffort(double effort) + { + return effort * AlephiumConstants.Pow2xDiff1TargetNumZero; + } + + #endregion // IPayoutHandler + + private class PaymentException : Exception + { + public PaymentException(string msg) : base(msg) + { + } + } + + private void ReportAndRethrowApiError(string action, Exception ex, bool rethrow = true) + { + var error = ex.Message; + + if(ex is AlephiumApiException apiException) + error = apiException.Response; + + logger.Warn(() => $"{action}: {error}"); + + if(rethrow) + throw ex; + } + + private async Task UnlockWallet(CancellationToken ct) + { + logger.Info(() => $"[{LogCategory}] Unlocking wallet: {extraPoolPaymentProcessingConfig.WalletName}"); + + var walletPassword = extraPoolPaymentProcessingConfig.WalletPassword ?? string.Empty; + + await Guard(() => alephiumClient.NameUnlockAsync(extraPoolPaymentProcessingConfig.WalletName, new WalletUnlock {Password = walletPassword}, ct), ex => + { + if (ex is AlephiumApiException apiException) + { + var error = apiException.Response; + + if (error != null && !error.ToLower().Contains("already unlocked")) + throw new PaymentException($"Failed to unlock wallet: {error}"); + } + + else + throw ex; + }); + + logger.Info(() => $"[{LogCategory}] Wallet: {extraPoolPaymentProcessingConfig.WalletName} unlocked"); + } + + private async Task LockWallet(CancellationToken ct) + { + logger.Info(() => $"[{LogCategory}] Locking wallet: {extraPoolPaymentProcessingConfig.WalletName}"); + + await Guard(() => alephiumClient.NameLockAsync(extraPoolPaymentProcessingConfig.WalletName, ct), + ex => ReportAndRethrowApiError("Failed to lock wallet", ex)); + + logger.Info(() => $"[{LogCategory}] Wallet: {extraPoolPaymentProcessingConfig.WalletName} is locked"); + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumPool.cs b/src/Miningcore/Blockchain/Alephium/AlephiumPool.cs new file mode 100644 index 000000000..31e9e79d7 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumPool.cs @@ -0,0 +1,395 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Numerics; +using Autofac; +using AutoMapper; +using Microsoft.IO; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Alephium.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 Miningcore.Util; +using Newtonsoft.Json; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Alephium; + +[CoinFamily(CoinFamily.Alephium)] +public class AlephiumPool : PoolBase +{ + public AlephiumPool(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) + { + } + + protected AlephiumJobParams currentJobParams; + protected AlephiumJobManager manager; + private AlephiumPoolConfigExtra extraPoolConfig; + private AlephiumCoinTemplate 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(); + + await connection.RespondAsync(connection.ConnectionId, request.Id); + + // setup worker context + context.IsSubscribed = true; + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); + } + + 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(); + var requestParams = request.ParamsAs(); + 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.ValidateAddress(minerName, ct); + context.Miner = minerName; + context.Worker = workerName; + + if(context.IsAuthorized) + { + // Despite having a subscribe method in their stratum RPC protocol: https://wiki.alephium.org/mining/alephium-stratum/, no mining software seems to use it, everyone just go straight to authorize, so we need to handle it somehow :/ + if(!context.IsSubscribed) + { + // setup worker context + context.IsSubscribed = true; + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); + } + + // respond + await connection.RespondAsync(context.IsAuthorized, request.Id); + + // send extranonce + await connection.NotifyAsync(AlephiumStratumMethods.SetExtraNonce, manager.GetSubscriberData(connection)); + + // log association + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); + + // 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}"); + } + + // send intial job + await SendJob(connection, context, currentJobParams); + } + + 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); + } + } + } + + 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 AlephiumStratumException(AlephiumStratumError.InvalidWorker, "unauthorized worker"); + else if(!context.IsSubscribed) + throw new AlephiumStratumException(AlephiumStratumError.InvalidWorker, "not subscribed"); + + var requestParams = request.ParamsAs(); + + // submit + var share = await manager.SubmitShareAsync(connection, requestParams, ct); + await connection.RespondAsync(true, request.Id); + + // 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 * AlephiumConstants.ShareMultiplier, 3)}"); + + // update pool stats + if(share.IsBlockCandidate) + poolStats.LastPoolBlockTime = clock.Now; + + // update client stats + context.Stats.ValidShares++; + + await UpdateVarDiffAsync(connection, false, ct); + } + + catch(AlephiumStratumException 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(AlephiumJobParams jobParams) + { + currentJobParams = jobParams; + + logger.Info(() => $"Broadcasting job {jobParams.JobId}"); + + await Guard(() => ForEachMinerAsync(async (connection, ct) => + { + var context = connection.ContextAs(); + + await SendJob(connection, context, currentJobParams); + })); + } + + private async Task SendJob(StratumConnection connection, AlephiumWorkerContext context, AlephiumJobParams jobParams) + { + var target = EncodeTarget(context.Difficulty); + + // clone job params + var jobParamsActual = new AlephiumJobParams + { + JobId = jobParams.JobId, + FromGroup = jobParams.FromGroup, + ToGroup = jobParams.ToGroup, + HeaderBlob = jobParams.HeaderBlob, + TxsBlob = jobParams.TxsBlob, + TargetBlob = target, + }; + + // send difficulty + await connection.NotifyAsync(AlephiumStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // send job + await connection.NotifyAsync(AlephiumStratumMethods.MiningNotify, new object[] { jobParamsActual }); + } + + public override double HashrateFromShares(double shares, double interval) + { + var multiplier = 16 * AlephiumConstants.Pow2xDiff1TargetNumZero; + var result = shares * multiplier / interval; + + return result; + } + + public override double ShareMultiplier => AlephiumConstants.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 ?? 2; + + manager = ctx.Resolve( + new TypedParameter(typeof(IExtraNonceProvider), new AlephiumExtraNonceProvider(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 AlephiumWorkerContext(); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + try + { + switch(request.Method) + { + case AlephiumStratumMethods.Subscribe: + await OnSubscribeAsync(connection, tsRequest); + break; + + case AlephiumStratumMethods.Authorize: + await OnAuthorizeAsync(connection, tsRequest, ct); + break; + + case AlephiumStratumMethods.SubmitShare: + await OnSubmitAsync(connection, tsRequest, ct); + break; + + case AlephiumStratumMethods.SubmitHashrate: + 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 GetNicehashStaticMinDiff(WorkerContextBase context, string coinName, string algoName) + { + var result = await base.GetNicehashStaticMinDiff(context, coinName, algoName); + + // adjust value to fit with our target value calculation + if(result.HasValue) + result = result.Value / uint.MaxValue; + + return result; + } + + protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) + { + await base.OnVarDiffUpdateAsync(connection, newDiff, ct); + + var context = connection.ContextAs(); + + if(context.ApplyPendingDifficulty()) + { + // send job + await SendJob(connection, context, currentJobParams); + } + } + + private string EncodeTarget(double difficulty) + { + return AlephiumUtils.EncodeTarget(difficulty); + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumStratumError.cs b/src/Miningcore/Blockchain/Alephium/AlephiumStratumError.cs new file mode 100644 index 000000000..f6b0d377e --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumStratumError.cs @@ -0,0 +1,23 @@ +namespace Miningcore.Blockchain.Alephium; + +public enum AlephiumStratumError +{ + JobNotFound = 20, + InvalidJobChainIndex = 21, + InvalidWorker = 22, + InvalidNonce = 23, + DuplicatedShare = 24, + LowDifficultyShare = 25, + InvalidBlockChainIndex = 26, + MinusOne = -1 +} + +public class AlephiumStratumException : Exception +{ + public AlephiumStratumException(AlephiumStratumError code, string message) : base(message) + { + Code = code; + } + + public AlephiumStratumError Code { get; set; } +} diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumStratumMethods.cs b/src/Miningcore/Blockchain/Alephium/AlephiumStratumMethods.cs new file mode 100644 index 000000000..4ce46d2da --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumStratumMethods.cs @@ -0,0 +1,46 @@ +namespace Miningcore.Blockchain.Alephium; + +public class AlephiumStratumMethods +{ + /// + /// 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"; + + /// + /// This call simply dumps transactions used for given job. Thanks to this, miners now have + /// everything needed to reconstruct source block template used by the pool and they can + /// check if pool isn't doing something nasty + /// + public const string GetTransactions = "mining.get_transactions"; + + /// + /// Used to subscribe to work from a server, required before all other communication. + /// + public const string SetExtraNonce = "mining.set_extranonce"; + + /// + /// Ignored + /// + public const string SubmitHashrate = "alph_submitHashrate"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumUtils.cs b/src/Miningcore/Blockchain/Alephium/AlephiumUtils.cs new file mode 100644 index 000000000..e48a2776f --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumUtils.cs @@ -0,0 +1,95 @@ +using System; +using System.Globalization; +using System.Numerics; +using Miningcore.Util; +using NBitcoin; + +namespace Miningcore.Blockchain.Alephium; + +public static class AlephiumUtils +{ + public static string EncodeTarget(double difficulty) + { + BigInteger numerator = AlephiumConstants.Diff1Target * 1024; + BigInteger denominator = (BigInteger)(Math.Ceiling(difficulty * 1024)); + BigInteger target = BigInteger.Divide(numerator, denominator); + byte[] targetBytes = target.ToByteArray(); + Array.Reverse(targetBytes); // Reverse the byte order to match endianness + byte[] paddedTargetBytes = new byte[Math.Max(targetBytes.Length, 32)]; + Buffer.BlockCopy(targetBytes, 0, paddedTargetBytes, paddedTargetBytes.Length - targetBytes.Length, Math.Min(targetBytes.Length, paddedTargetBytes.Length)); + return BitConverter.ToString(paddedTargetBytes).Replace("-", "").ToLower(); + } + + public static (int fromGroup, int toGroup) BlockChainIndex(Span hashBytes) + { + byte beforeLast = hashBytes[hashBytes.Length - 2]; + beforeLast = (byte)(beforeLast & 0xFF); + byte last = hashBytes[hashBytes.Length -1]; + last = (byte)(last & 0xFF); + var bigIndex = (beforeLast << 8) | last; + var chainNum = AlephiumConstants.GroupSize * AlephiumConstants.GroupSize; + var index = bigIndex % chainNum; + double tmpFromGroup = index / AlephiumConstants.GroupSize; + int fromGroup = (int) Math.Floor(tmpFromGroup); + int toGroup = index % AlephiumConstants.GroupSize; + return (fromGroup, toGroup); + } + + public static double TranslateApiHashrate(string hashrate) + { + double result = 0; + + if (!string.IsNullOrEmpty(hashrate)) + { + string[] hashrateWithUnit = hashrate.Split(" "); + if (hashrateWithUnit.Length == 2) + { + result = (double) ConvertNumberFromApi(hashrateWithUnit[0]); + + switch(hashrateWithUnit[1].ToLower()) + { + case "zh/s": + result = result * (double) BigInteger.Parse("1000000000000000000000"); + break; + case "eh/s": + result = result * (double) BigInteger.Parse("1000000000000000000"); + break; + case "ph/s": + result = result * (double) BigInteger.Parse("1000000000000000"); + break; + case "th/s": + result = result * (double) BigInteger.Parse("1000000000000"); + break; + case "gh/s": + result = result * (double) BigInteger.Parse("1000000000"); + break; + case "mh/s": + result = result * (double) BigInteger.Parse("1000000"); + break; + case "kh/s": + result = result * (double) BigInteger.Parse("1000"); + break; + } + } + } + + return result; + } + + public static string ConvertNumberForApi(decimal amount) + { + return Convert.ToString(Math.Round(amount)); + } + + public static decimal ConvertNumberFromApi(string amount) + { + return Convert.ToDecimal(amount); + } + + public static long UnixTimeStampForApi(DateTime date) + { + long unixTimeStamp = date.ToUniversalTime().Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks; + unixTimeStamp /= TimeSpan.TicksPerMillisecond; + return unixTimeStamp; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs b/src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs new file mode 100644 index 000000000..a6a91d0d9 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/AlephiumWorkerContext.cs @@ -0,0 +1,30 @@ +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Alephium; + +public class AlephiumWorkerSubmitParams +{ + public string JobId { get; init; } + public int FromGroup { get; init; } + public int ToGroup { get; init; } + public string Nonce { get; init; } + public string Worker { get; init; } +} + +public class AlephiumWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumDaemonEndpointConfigExtra.cs b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumDaemonEndpointConfigExtra.cs new file mode 100644 index 000000000..9407ccfde --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumDaemonEndpointConfigExtra.cs @@ -0,0 +1,14 @@ +namespace Miningcore.Blockchain.Alephium.Configuration; + +public class AlephiumDaemonEndpointConfigExtra +{ + /// + /// The Alephium Node's API key in clear-text - not the hash + /// + public string ApiKey { get; set; } + + /// + /// The Alephium Node's Miner API Port + /// + public int MinerApiPort { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs new file mode 100644 index 000000000..05f94e1fe --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPaymentProcessingConfigExtra.cs @@ -0,0 +1,25 @@ +namespace Miningcore.Blockchain.Alephium.Configuration; + +public class AlephiumPaymentProcessingConfigExtra +{ + /// + /// Name of the wallet to use + /// + public string WalletName { get; set; } + + /// + /// Password for unlocking wallet + /// + public string WalletPassword { get; set; } + + /// + /// WARNING: DO NOT USE ON MAINNET UNLESS YOU KNOW WHAT YOU ARE DOING + /// The sole purpose of that option is to mimic the long (mainnet) block rewards "lock time" mechanism on TESTNET!!! + /// + public long? BlockRewardsLockTime { get; set; } + + /// + /// True to exempt transaction fees from miner rewards + /// + public bool KeepTransactionFees { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPoolConfigExtra.cs b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPoolConfigExtra.cs new file mode 100644 index 000000000..5844e28ea --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/Configuration/AlephiumPoolConfigExtra.cs @@ -0,0 +1,20 @@ +using Miningcore.Configuration; + +namespace Miningcore.Blockchain.Alephium.Configuration; + +public class AlephiumPoolConfigExtra +{ + /// + /// Maximum number of tracked jobs. + /// Default: 8 + /// + public int? MaxActiveJobs { get; set; } + + /// + /// Maximum size of buffer when receiving job message + /// Default: 131072 + /// + public int? SocketJobMessageBufferSize { get; set; } + + public int? ExtraNonce1Size { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Alephium/RPC/AlephiumClient.cs b/src/Miningcore/Blockchain/Alephium/RPC/AlephiumClient.cs new file mode 100644 index 000000000..9207d8854 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/RPC/AlephiumClient.cs @@ -0,0 +1,13536 @@ +//---------------------- +// +// Generated using the NSwag toolchain v13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#nullable enable + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" + +namespace Miningcore.Blockchain.Alephium +{ + using System = global::System; + using System.Numerics; + using Newtonsoft.Json.Linq; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AlephiumClient + { + private string _baseUrl = "/"; + private System.Net.Http.HttpClient _httpClient; + private System.Lazy _settings; + + public AlephiumClient(string baseUrl, HttpClient httpClient) + { + BaseUrl = baseUrl; + _httpClient = httpClient; + _settings = new Lazy(CreateSerializerSettings); + } + + private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set { _baseUrl = value; } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + + /// + /// List available wallets + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> GetWalletsAsync() + { + return GetWalletsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List available wallets + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> GetWalletsAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Restore a wallet from your mnemonic + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PutWalletsAsync(WalletRestore body) + { + return PutWalletsAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Restore a wallet from your mnemonic + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PutWalletsAsync(WalletRestore body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create a new wallet + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostWalletsAsync(WalletCreation body) + { + return PostWalletsAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create a new wallet + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostWalletsAsync(WalletCreation body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get info about that node + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetInfosNodeAsync() + { + return GetInfosNodeAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get info about that node + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetInfosNodeAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/node"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get version about that node + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetInfosVersionAsync() + { + return GetInfosVersionAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get version about that node + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetInfosVersionAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/version"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get key params about your blockchain + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetInfosChainParamsAsync() + { + return GetInfosChainParamsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get key params about your blockchain + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetInfosChainParamsAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/chain-params"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get info about your own clique + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetInfosSelfCliqueAsync() + { + return GetInfosSelfCliqueAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get info about your own clique + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetInfosSelfCliqueAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/self-clique"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get infos about the inter cliques + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> GetInfosInterCliquePeerInfoAsync() + { + return GetInfosInterCliquePeerInfoAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get infos about the inter cliques + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> GetInfosInterCliquePeerInfoAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/inter-clique-peer-info"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get discovered neighbors + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> GetInfosDiscoveredNeighborsAsync() + { + return GetInfosDiscoveredNeighborsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get discovered neighbors + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> GetInfosDiscoveredNeighborsAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/discovered-neighbors"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the misbehaviors of peers + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> GetInfosMisbehaviorsAsync() + { + return GetInfosMisbehaviorsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the misbehaviors of peers + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> GetInfosMisbehaviorsAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/misbehaviors"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Ban/Unban given peers + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostInfosMisbehaviorsAsync(Ban body) + { + return PostInfosMisbehaviorsAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Ban/Unban given peers + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostInfosMisbehaviorsAsync(Ban body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/misbehaviors"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the unreachable brokers + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> GetInfosUnreachableAsync() + { + return GetInfosUnreachableAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the unreachable brokers + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> GetInfosUnreachableAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/unreachable"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Set brokers to be unreachable/reachable + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostInfosDiscoveryAsync(DiscoveryAction body) + { + return PostInfosDiscoveryAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Set brokers to be unreachable/reachable + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostInfosDiscoveryAsync(DiscoveryAction body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/discovery"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get history average hashrate on the given time interval + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetInfosHistoryHashrateAsync(long fromTs, long? toTs) + { + return GetInfosHistoryHashrateAsync(fromTs, toTs, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get history average hashrate on the given time interval + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetInfosHistoryHashrateAsync(long fromTs, long? toTs, System.Threading.CancellationToken cancellationToken) + { + if (fromTs == null) + throw new System.ArgumentNullException("fromTs"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/history-hashrate?"); + urlBuilder_.Append(System.Uri.EscapeDataString("fromTs") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromTs, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + if (toTs != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("toTs") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toTs, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get average hashrate from `now - timespan(millis)` to `now` + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetInfosCurrentHashrateAsync(long? timespan) + { + return GetInfosCurrentHashrateAsync(timespan, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get average hashrate from `now - timespan(millis)` to `now` + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetInfosCurrentHashrateAsync(long? timespan, System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/current-hashrate?"); + if (timespan != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("timespan") + "=").Append(System.Uri.EscapeDataString(ConvertToString(timespan, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the average difficulty of the latest blocks from all shards + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetInfosCurrentDifficultyAsync() + { + return GetInfosCurrentDifficultyAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the average difficulty of the latest blocks from all shards + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetInfosCurrentDifficultyAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/infos/current-difficulty"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List blocks on the given time interval + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBlockflowBlocksAsync(long fromTs, long? toTs) + { + return GetBlockflowBlocksAsync(fromTs, toTs, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List blocks on the given time interval + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBlockflowBlocksAsync(long fromTs, long? toTs, System.Threading.CancellationToken cancellationToken) + { + if (fromTs == null) + throw new System.ArgumentNullException("fromTs"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/blocks?"); + urlBuilder_.Append(System.Uri.EscapeDataString("fromTs") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromTs, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + if (toTs != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("toTs") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toTs, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List blocks with events on the given time interval + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBlockflowBlocksWithEventsAsync(long fromTs, long? toTs) + { + return GetBlockflowBlocksWithEventsAsync(fromTs, toTs, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List blocks with events on the given time interval + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBlockflowBlocksWithEventsAsync(long fromTs, long? toTs, System.Threading.CancellationToken cancellationToken) + { + if (fromTs == null) + throw new System.ArgumentNullException("fromTs"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/blocks-with-events?"); + urlBuilder_.Append(System.Uri.EscapeDataString("fromTs") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromTs, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + if (toTs != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("toTs") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toTs, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Check if the block is in main chain + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBlockflowIsBlockInMainChainAsync(string blockHash) + { + return GetBlockflowIsBlockInMainChainAsync(blockHash, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Check if the block is in main chain + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBlockflowIsBlockInMainChainAsync(string blockHash, System.Threading.CancellationToken cancellationToken) + { + if (blockHash == null) + throw new System.ArgumentNullException("blockHash"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/is-block-in-main-chain?"); + urlBuilder_.Append(System.Uri.EscapeDataString("blockHash") + "=").Append(System.Uri.EscapeDataString(ConvertToString(blockHash, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the balance of an address + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr`
+ /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetAddressesAddressBalanceAsync(string address, bool? mempool) + { + return GetAddressesAddressBalanceAsync(address, mempool, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the balance of an address + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr`
+ /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetAddressesAddressBalanceAsync(string address, bool? mempool, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/addresses/{address}/balance?"); + urlBuilder_.Replace("{address}", System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + if (mempool != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("mempool") + "=").Append(System.Uri.EscapeDataString(ConvertToString(mempool, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the UTXOs of an address + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetAddressesAddressUtxosAsync(string address) + { + return GetAddressesAddressUtxosAsync(address, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the UTXOs of an address + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetAddressesAddressUtxosAsync(string address, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/addresses/{address}/utxos"); + urlBuilder_.Replace("{address}", System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get the group of an address + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetAddressesAddressGroupAsync(string address) + { + return GetAddressesAddressGroupAsync(address, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get the group of an address + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetAddressesAddressGroupAsync(string address, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/addresses/{address}/group"); + urlBuilder_.Replace("{address}", System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get all block's hashes at given height for given groups + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBlockflowHashesAsync(int fromGroup, int toGroup, int height) + { + return GetBlockflowHashesAsync(fromGroup, toGroup, height, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get all block's hashes at given height for given groups + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBlockflowHashesAsync(int fromGroup, int toGroup, int height, System.Threading.CancellationToken cancellationToken) + { + if (fromGroup == null) + throw new System.ArgumentNullException("fromGroup"); + + if (toGroup == null) + throw new System.ArgumentNullException("toGroup"); + + if (height == null) + throw new System.ArgumentNullException("height"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/hashes?"); + urlBuilder_.Append(System.Uri.EscapeDataString("fromGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Append(System.Uri.EscapeDataString("toGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Append(System.Uri.EscapeDataString("height") + "=").Append(System.Uri.EscapeDataString(ConvertToString(height, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get infos about the chain from the given groups + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetBlockflowChainInfoAsync(int fromGroup, int toGroup) + { + return GetBlockflowChainInfoAsync(fromGroup, toGroup, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get infos about the chain from the given groups + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetBlockflowChainInfoAsync(int fromGroup, int toGroup, System.Threading.CancellationToken cancellationToken) + { + if (fromGroup == null) + throw new System.ArgumentNullException("fromGroup"); + + if (toGroup == null) + throw new System.ArgumentNullException("toGroup"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/chain-info?"); + urlBuilder_.Append(System.Uri.EscapeDataString("fromGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Append(System.Uri.EscapeDataString("toGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Build an unsigned transaction to a number of recipients + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr` + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostTransactionsBuildAsync(BuildSettlement body) + { + return PostTransactionsBuildAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Build an unsigned transaction to a number of recipients + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr` + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostTransactionsBuildAsync(BuildSettlement body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/transactions/build"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Build unsigned transactions to send all unlocked ALPH and token balances of one address to another address + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostTransactionsSweepAddressBuildAsync(BuildSweepAddressSettlements body) + { + return PostTransactionsSweepAddressBuildAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Build unsigned transactions to send all unlocked ALPH and token balances of one address to another address + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostTransactionsSweepAddressBuildAsync(BuildSweepAddressSettlements body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/transactions/sweep-address/build"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Submit a signed transaction + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostTransactionsSubmitAsync(SubmitSettlement body) + { + return PostTransactionsSubmitAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Submit a signed transaction + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostTransactionsSubmitAsync(SubmitSettlement body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/transactions/submit"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Decode an unsigned transaction + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostTransactionsDecodeUnsignedTxAsync(DecodeUnsignedTx body) + { + return PostTransactionsDecodeUnsignedTxAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Decode an unsigned transaction + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostTransactionsDecodeUnsignedTxAsync(DecodeUnsignedTx body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/transactions/decode-unsigned-tx"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get transaction details + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTransactionsDetailsTxidAsync(string txId, int? fromGroup, int? toGroup) + { + return GetTransactionsDetailsTxidAsync(txId, fromGroup, toGroup, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get transaction details + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTransactionsDetailsTxidAsync(string txId, int? fromGroup, int? toGroup, System.Threading.CancellationToken cancellationToken) + { + if (txId == null) + throw new System.ArgumentNullException("txId"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/transactions/details/{txId}?"); + urlBuilder_.Replace("{txId}", System.Uri.EscapeDataString(ConvertToString(txId, System.Globalization.CultureInfo.InvariantCulture))); + if (fromGroup != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("fromGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + if (toGroup != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("toGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get tx status + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetTransactionsStatusAsync(string txId, int? fromGroup, int? toGroup) + { + return GetTransactionsStatusAsync(txId, fromGroup, toGroup, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get tx status + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetTransactionsStatusAsync(string txId, int? fromGroup, int? toGroup, System.Threading.CancellationToken cancellationToken) + { + if (txId == null) + throw new System.ArgumentNullException("txId"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/transactions/status?"); + urlBuilder_.Append(System.Uri.EscapeDataString("txId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(txId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + if (fromGroup != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("fromGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + if (toGroup != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("toGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List mempool transactions + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> GetMempoolTransactionsAsync() + { + return GetMempoolTransactionsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List mempool transactions + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> GetMempoolTransactionsAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/mempool/transactions"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Remove all transactions from mempool + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task DeleteMempoolTransactionsAsync() + { + return DeleteMempoolTransactionsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Remove all transactions from mempool + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task DeleteMempoolTransactionsAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/mempool/transactions"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Rebroadcase a mempool transaction to the network + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PutMempoolTransactionsRebroadcastAsync(string txId) + { + return PutMempoolTransactionsRebroadcastAsync(txId, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Rebroadcase a mempool transaction to the network + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PutMempoolTransactionsRebroadcastAsync(string txId, System.Threading.CancellationToken cancellationToken) + { + if (txId == null) + throw new System.ArgumentNullException("txId"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/mempool/transactions/rebroadcast?"); + urlBuilder_.Append(System.Uri.EscapeDataString("txId") + "=").Append(System.Uri.EscapeDataString(ConvertToString(txId, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("PUT"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Validate all mempool transactions and remove invalid ones + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PutMempoolTransactionsValidateAsync() + { + return PutMempoolTransactionsValidateAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Validate all mempool transactions and remove invalid ones + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PutMempoolTransactionsValidateAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/mempool/transactions/validate"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("PUT"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Compile a script + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsCompileScriptAsync(Script body) + { + return PostContractsCompileScriptAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Compile a script + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsCompileScriptAsync(Script body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/compile-script"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Build an unsigned script + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsUnsignedTxExecuteScriptAsync(BuildExecuteScriptTx body) + { + return PostContractsUnsignedTxExecuteScriptAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Build an unsigned script + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsUnsignedTxExecuteScriptAsync(BuildExecuteScriptTx body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/unsigned-tx/execute-script"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Compile a smart contract + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsCompileContractAsync(Deal body) + { + return PostContractsCompileContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Compile a smart contract + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsCompileContractAsync(Deal body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/compile-contract"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Compile a project + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsCompileProjectAsync(Project body) + { + return PostContractsCompileProjectAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Compile a project + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsCompileProjectAsync(Project body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/compile-project"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Build an unsigned contract + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsUnsignedTxDeployContractAsync(BuildDeployDealTx body) + { + return PostContractsUnsignedTxDeployContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Build an unsigned contract + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsUnsignedTxDeployContractAsync(BuildDeployDealTx body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/unsigned-tx/deploy-contract"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get contract state + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetContractsAddressStateAsync(string address, int group) + { + return GetContractsAddressStateAsync(address, group, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get contract state + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetContractsAddressStateAsync(string address, int group, System.Threading.CancellationToken cancellationToken) + { + if (address == null) + throw new System.ArgumentNullException("address"); + + if (group == null) + throw new System.ArgumentNullException("group"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/{address}/state?"); + urlBuilder_.Replace("{address}", System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append(System.Uri.EscapeDataString("group") + "=").Append(System.Uri.EscapeDataString(ConvertToString(group, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Test contract + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsTestContractAsync(TestDeal body) + { + return PostContractsTestContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Test contract + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsTestContractAsync(TestDeal body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/test-contract"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Call contract + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsCallContractAsync(CallDeal body) + { + return PostContractsCallContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Call contract + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsCallContractAsync(CallDeal body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/call-contract"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Multiple call contract + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostContractsMulticallContractAsync(MultipleCallDeal body) + { + return PostContractsMulticallContractAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Multiple call contract + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostContractsMulticallContractAsync(MultipleCallDeal body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/contracts/multicall-contract"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Create the multisig address and unlock script + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr` + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostMultisigAddressAsync(BuildMultisigAddress body) + { + return PostMultisigAddressAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Create the multisig address and unlock script + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr` + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostMultisigAddressAsync(BuildMultisigAddress body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/multisig/address"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Build a multisig unsigned transaction + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostMultisigBuildAsync(BuildMultisig body) + { + return PostMultisigBuildAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Build a multisig unsigned transaction + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostMultisigBuildAsync(BuildMultisig body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/multisig/build"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Submit a multi-signed transaction + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostMultisigSubmitAsync(SubmitMultisig body) + { + return PostMultisigSubmitAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Submit a multi-signed transaction + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostMultisigSubmitAsync(SubmitMultisig body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/multisig/submit"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Verify the SecP256K1 signature of some data + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostUtilsVerifySignatureAsync(VerifySignature body) + { + return PostUtilsVerifySignatureAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Verify the SecP256K1 signature of some data + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostUtilsVerifySignatureAsync(VerifySignature body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/utils/verify-signature"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Check and repair the indexing of block hashes + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PutUtilsCheckHashIndexingAsync() + { + return PutUtilsCheckHashIndexingAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Check and repair the indexing of block hashes + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PutUtilsCheckHashIndexingAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/utils/check-hash-indexing"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("PUT"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Execute an action on CPU miner. !!! for test only !!! + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostMinersCpuMiningAsync(string action) + { + return PostMinersCpuMiningAsync(action, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Execute an action on CPU miner. !!! for test only !!! + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostMinersCpuMiningAsync(string action, System.Threading.CancellationToken cancellationToken) + { + if (action == null) + throw new System.ArgumentNullException("action"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/miners/cpu-mining?"); + urlBuilder_.Append(System.Uri.EscapeDataString("action") + "=").Append(System.Uri.EscapeDataString(ConvertToString(action, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Mine a block on CPU miner. !!! for test only !!! + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PostMinersCpuMiningMineOneBlockAsync(int fromGroup, int toGroup) + { + return PostMinersCpuMiningMineOneBlockAsync(fromGroup, toGroup, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Mine a block on CPU miner. !!! for test only !!! + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PostMinersCpuMiningMineOneBlockAsync(int fromGroup, int toGroup, System.Threading.CancellationToken cancellationToken) + { + if (fromGroup == null) + throw new System.ArgumentNullException("fromGroup"); + + if (toGroup == null) + throw new System.ArgumentNullException("toGroup"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/miners/cpu-mining/mine-one-block?"); + urlBuilder_.Append(System.Uri.EscapeDataString("fromGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(fromGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Append(System.Uri.EscapeDataString("toGroup") + "=").Append(System.Uri.EscapeDataString(ConvertToString(toGroup, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List miner's addresses + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetMinersAddressesAsync() + { + return GetMinersAddressesAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List miner's addresses + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetMinersAddressesAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/miners/addresses"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Update miner's addresses, but better to use user.conf instead + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PutMinersAddressesAsync(MinerAddresses body) + { + return PutMinersAddressesAsync(body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Update miner's addresses, but better to use user.conf instead + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PutMinersAddressesAsync(MinerAddresses body, System.Threading.CancellationToken cancellationToken) + { + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/miners/addresses"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("PUT"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get events for a contract within a counter range + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetEventsContractContractaddressAsync(string contractAddress, int start, int? limit, int? group) + { + return GetEventsContractContractaddressAsync(contractAddress, start, limit, group, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get events for a contract within a counter range + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetEventsContractContractaddressAsync(string contractAddress, int start, int? limit, int? group, System.Threading.CancellationToken cancellationToken) + { + if (contractAddress == null) + throw new System.ArgumentNullException("contractAddress"); + + if (start == null) + throw new System.ArgumentNullException("start"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/events/contract/{contractAddress}?"); + urlBuilder_.Replace("{contractAddress}", System.Uri.EscapeDataString(ConvertToString(contractAddress, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append(System.Uri.EscapeDataString("start") + "=").Append(System.Uri.EscapeDataString(ConvertToString(start, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + if (limit != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("limit") + "=").Append(System.Uri.EscapeDataString(ConvertToString(limit, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + if (group != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("group") + "=").Append(System.Uri.EscapeDataString(ConvertToString(group, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get current value of the events counter for a contract + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetEventsContractContractaddressCurrentCountAsync(string contractAddress) + { + return GetEventsContractContractaddressCurrentCountAsync(contractAddress, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get current value of the events counter for a contract + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetEventsContractContractaddressCurrentCountAsync(string contractAddress, System.Threading.CancellationToken cancellationToken) + { + if (contractAddress == null) + throw new System.ArgumentNullException("contractAddress"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/events/contract/{contractAddress}/current-count"); + urlBuilder_.Replace("{contractAddress}", System.Uri.EscapeDataString(ConvertToString(contractAddress, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get contract events for a transaction + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetEventsTxIdTxidAsync(string txId, int? group) + { + return GetEventsTxIdTxidAsync(txId, group, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get contract events for a transaction + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetEventsTxIdTxidAsync(string txId, int? group, System.Threading.CancellationToken cancellationToken) + { + if (txId == null) + throw new System.ArgumentNullException("txId"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/events/tx-id/{txId}?"); + urlBuilder_.Replace("{txId}", System.Uri.EscapeDataString(ConvertToString(txId, System.Globalization.CultureInfo.InvariantCulture))); + if (group != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("group") + "=").Append(System.Uri.EscapeDataString(ConvertToString(group, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get contract events for a block + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetEventsBlockHashBlockhashAsync(string blockHash, int? group) + { + return GetEventsBlockHashBlockhashAsync(blockHash, group, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get contract events for a block + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetEventsBlockHashBlockhashAsync(string blockHash, int? group, System.Threading.CancellationToken cancellationToken) + { + if (blockHash == null) + throw new System.ArgumentNullException("blockHash"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/events/block-hash/{blockHash}?"); + urlBuilder_.Replace("{blockHash}", System.Uri.EscapeDataString(ConvertToString(blockHash, System.Globalization.CultureInfo.InvariantCulture))); + if (group != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("group") + "=").Append(System.Uri.EscapeDataString(ConvertToString(group, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T)!, string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody!, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new AlephiumApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody!, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new AlephiumApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object? value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array) value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + var result = System.Convert.ToString(value, cultureInfo); + return result == null ? "" : result; + } + + /// + /// Get wallet's status + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameAsync(string wallet_name) + { + return NameAsync(wallet_name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get wallet's status + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameAsync(string wallet_name, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get your total balance + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr`
+ /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameBalancesAsync(string wallet_name) + { + return NameBalancesAsync(wallet_name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get your total balance + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr`
+ /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameBalancesAsync(string wallet_name, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/balances"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List all your wallet's addresses + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameAddressesAsync(string wallet_name) + { + return NameAddressesAsync(wallet_name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List all your wallet's addresses + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameAddressesAsync(string wallet_name, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/addresses"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get address' info + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameAddressesAddressAsync(string wallet_name, string address) + { + return NameAddressesAddressAsync(wallet_name, address, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get address' info + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameAddressesAddressAsync(string wallet_name, string address, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (address == null) + throw new System.ArgumentNullException("address"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/addresses/{address}"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Replace("{address}", System.Uri.EscapeDataString(ConvertToString(address, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// List all miner addresses per group + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> NameMinerAddressesAsync(string wallet_name) + { + return NameMinerAddressesAsync(wallet_name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// List all miner addresses per group + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> NameMinerAddressesAsync(string wallet_name, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/miner-addresses"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Delete your wallet file (can be recovered with your mnemonic) + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameAsync(string wallet_name, WalletDeletion body) + { + return NameAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Delete your wallet file (can be recovered with your mnemonic) + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameAsync(string wallet_name, WalletDeletion body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Lock your wallet + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameLockAsync(string wallet_name) + { + return NameLockAsync(wallet_name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Lock your wallet + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameLockAsync(string wallet_name, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/lock"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Unlock your wallet + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameUnlockAsync(string wallet_name, WalletUnlock body) + { + return NameUnlockAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Unlock your wallet + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameUnlockAsync(string wallet_name, WalletUnlock body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/unlock"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Reveal your mnemonic. !!! use it with caution !!! + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameRevealMnemonicAsync(string wallet_name, RevealMnemonic body) + { + return NameRevealMnemonicAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Reveal your mnemonic. !!! use it with caution !!! + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameRevealMnemonicAsync(string wallet_name, RevealMnemonic body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/reveal-mnemonic"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Transfer ALPH from the active address + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr` + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameTransferAsync(string wallet_name, Transfer body) + { + return NameTransferAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Transfer ALPH from the active address + /// + /// Format 1: `1000000000000000000` + ///
+ ///
Format 2: `x.y ALPH`, where `1 ALPH = 1000000000000000000 + ///
+ ///
Field fromPublicKeyType can be `default` or `bip340-schnorr` + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameTransferAsync(string wallet_name, Transfer body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/transfer"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Transfer all unlocked ALPH from the active address to another address + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameSweepActiveAddressAsync(string wallet_name, Sweep body) + { + return NameSweepActiveAddressAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Transfer all unlocked ALPH from the active address to another address + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameSweepActiveAddressAsync(string wallet_name, Sweep body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/sweep-active-address"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Transfer unlocked ALPH from all addresses (including all mining addresses if applicable) to another address + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameSweepAllAddressesAsync(string wallet_name, Sweep body) + { + return NameSweepAllAddressesAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Transfer unlocked ALPH from all addresses (including all mining addresses if applicable) to another address + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameSweepAllAddressesAsync(string wallet_name, Sweep body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/sweep-all-addresses"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Sign the given data and return back the signature + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameSignAsync(string wallet_name, Sign body) + { + return NameSignAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Sign the given data and return back the signature + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameSignAsync(string wallet_name, Sign body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/sign"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Derive your next address + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameDeriveNextAddressAsync(string wallet_name, int? group) + { + return NameDeriveNextAddressAsync(wallet_name, group, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Derive your next address + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameDeriveNextAddressAsync(string wallet_name, int? group, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/derive-next-address?"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + if (group != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("group") + "=").Append(System.Uri.EscapeDataString(ConvertToString(group, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Derive your next miner addresses for each group + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task> NameDeriveNextMinerAddressesAsync(string wallet_name) + { + return NameDeriveNextMinerAddressesAsync(wallet_name, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Derive your next miner addresses for each group + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task> NameDeriveNextMinerAddressesAsync(string wallet_name, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/derive-next-miner-addresses"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Choose the active address + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task NameChangeActiveAddressAsync(string wallet_name, ChangeActiveAddress body) + { + return NameChangeActiveAddressAsync(wallet_name, body, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Choose the active address + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task NameChangeActiveAddressAsync(string wallet_name, ChangeActiveAddress body, System.Threading.CancellationToken cancellationToken) + { + if (wallet_name == null) + throw new System.ArgumentNullException("wallet_name"); + + if (body == null) + throw new System.ArgumentNullException("body"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/wallets/{wallet_name}/change-active-address"); + urlBuilder_.Replace("{wallet_name}", System.Uri.EscapeDataString(ConvertToString(wallet_name, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value)); + content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + return; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get a block with hash + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task HashAsync(string block_hash) + { + return HashAsync(block_hash, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get a block with hash + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task HashAsync(string block_hash, System.Threading.CancellationToken cancellationToken) + { + if (block_hash == null) + throw new System.ArgumentNullException("block_hash"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/blocks/{block_hash}"); + urlBuilder_.Replace("{block_hash}", System.Uri.EscapeDataString(ConvertToString(block_hash, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get a block and events with hash + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task HashBlockAndEventsAsync(string block_hash) + { + return HashBlockAndEventsAsync(block_hash, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get a block and events with hash + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task HashBlockAndEventsAsync(string block_hash, System.Threading.CancellationToken cancellationToken) + { + if (block_hash == null) + throw new System.ArgumentNullException("block_hash"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/blocks-with-events/{block_hash}"); + urlBuilder_.Replace("{block_hash}", System.Uri.EscapeDataString(ConvertToString(block_hash, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get block header + /// + /// A server side error occurred. + public virtual System.Threading.Tasks.Task HashBlockHeaderEntryAsync(string block_hash) + { + return HashBlockHeaderEntryAsync(block_hash, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get block header + /// + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task HashBlockHeaderEntryAsync(string block_hash, System.Threading.CancellationToken cancellationToken) + { + if (block_hash == null) + throw new System.ArgumentNullException("block_hash"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/blockflow/headers/{block_hash}"); + urlBuilder_.Replace("{block_hash}", System.Uri.EscapeDataString(ConvertToString(block_hash, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + await PrepareRequestAsync(client_, request_, urlBuilder_, cancellationToken).ConfigureAwait(false); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + await PrepareRequestAsync(client_, request_, url_, cancellationToken).ConfigureAwait(false); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + await ProcessResponseAsync(client_, response_, cancellationToken).ConfigureAwait(false); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("BadRequest", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 401) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("Unauthorized", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("NotFound", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 500) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("InternalServerError", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 503) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new AlephiumApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new AlephiumApiException("ServiceUnavailable", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new AlephiumApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AddressBalance + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("balance", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Balance { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("balanceHint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BalanceHint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockedBalance", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string LockedBalance { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockedBalanceHint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string LockedBalanceHint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("warning", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Warning { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AddressInfo + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string PublicKey { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("group", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Group { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("path", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Path { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Addresses + { + [Newtonsoft.Json.JsonProperty("activeAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ActiveAddress { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("addresses", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Addresses1 { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AssetInput + { + [Newtonsoft.Json.JsonProperty("outputRef", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public OutputRef OutputRef { get; set; } = new OutputRef(); + + [Newtonsoft.Json.JsonProperty("unlockScript", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnlockScript { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AssetOutput + { + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AssetState + { + [Newtonsoft.Json.JsonProperty("attoAlphAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string AttoAlphAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Tokens { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BadRequest + { + [Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Detail { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Aplomb + { + [Newtonsoft.Json.JsonProperty("balance", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Balance1 { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("balanceHint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BalanceHint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockedBalance", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string LockedBalance { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockedBalanceHint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string LockedBalanceHint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokenBalances", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection TokenBalances { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockedTokenBalances", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection LockedTokenBalances { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("utxoNum", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int UtxoNum { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("warning", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Warning { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Aplombs + { + [Newtonsoft.Json.JsonProperty("totalBalance", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TotalBalance { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("totalBalanceHint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TotalBalanceHint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("balances", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Balances1 { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Ban + { + [Newtonsoft.Json.JsonProperty("peers", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Peers { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Banned + { + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BlockAndEvents + { + [Newtonsoft.Json.JsonProperty("block", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public BlockEntry Block { get; set; } = new BlockEntry(); + + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BlockEntry + { + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Hash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long Timestamp { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("chainFrom", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ChainFrom { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("chainTo", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ChainTo { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("height", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public ulong Height { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("deps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Deps { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("nonce", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Nonce { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Version { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("depStateHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string DepStateHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txsHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxsHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("target", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Target { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BlockHeaderEntry + { + [Newtonsoft.Json.JsonProperty("hash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Hash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("timestamp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long Timestamp { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("chainFrom", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ChainFrom { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("chainTo", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ChainTo { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("height", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public ulong Height { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("deps", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Deps { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BlocksAndEventsPerTimeStampRange + { + [Newtonsoft.Json.JsonProperty("blocksAndEvents", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection> BlocksAndEvents { get; set; } = new System.Collections.ObjectModel.Collection>(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BlocksPerTimeStampRange + { + [Newtonsoft.Json.JsonProperty("blocks", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection> Blocks { get; set; } = new System.Collections.ObjectModel.Collection>(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BrokerInfo + { + [Newtonsoft.Json.JsonProperty("cliqueId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CliqueId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("brokerId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int BrokerId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("brokerNum", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int BrokerNum { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public Address Address { get; set; } = new Address(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildDeployDealTx + { + [Newtonsoft.Json.JsonProperty("fromPublicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromPublicKey { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromPublicKeyType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string FromPublicKeyType { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("initialAttoAlphAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string InitialAttoAlphAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("initialTokenAmounts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection InitialTokenAmounts { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("issueTokenAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string IssueTokenAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("targetBlockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TargetBlockHash { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildDeployDealTxResult + { + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnsignedTx { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildExecuteScriptTx + { + [Newtonsoft.Json.JsonProperty("fromPublicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromPublicKey { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromPublicKeyType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string FromPublicKeyType { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("attoAlphAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AttoAlphAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Tokens { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("targetBlockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TargetBlockHash { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildExecuteScriptTxResult + { + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnsignedTx { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildInfo + { + [Newtonsoft.Json.JsonProperty("releaseVersion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ReleaseVersion { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("commit", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Commit { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildMultisig + { + [Newtonsoft.Json.JsonProperty("fromAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromAddress { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromPublicKeys", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection FromPublicKeys { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("destinations", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Destinations { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Gas { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string GasPrice { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildMultisigAddress + { + [Newtonsoft.Json.JsonProperty("keys", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Keys { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("mrequired", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Mrequired { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildMultisigAddressResult + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildSweepAddressSettlements + { + [Newtonsoft.Json.JsonProperty("fromPublicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromPublicKey { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ToAddress { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("maxAttoAlphPerUTXO", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MaxAttoAlphPerUTXO { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockTime", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long LockTime { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("targetBlockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TargetBlockHash { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildSweepAddressSettlementsResult + { + [Newtonsoft.Json.JsonProperty("unsignedTxs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection UnsignedTxs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildSettlement + { + [Newtonsoft.Json.JsonProperty("fromPublicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FromPublicKey { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromPublicKeyType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string FromPublicKeyType { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("destinations", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Destinations { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("utxos", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Utxos { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("targetBlockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TargetBlockHash { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class BuildSettlementResult + { + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnsignedTx { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Args + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public string Type { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public string Value { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CallDeal + { + [Newtonsoft.Json.JsonProperty("group", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Group { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("worldStateBlockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string WorldStateBlockHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("methodIndex", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int MethodIndex { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("args", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Args { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("existingContracts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection ExistingContracts { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("inputAssets", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection InputAssets { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TxOutputs + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public string Type { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("hint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Hint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("key", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Key { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("attoAlphAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AttoAlphAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Tokens { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CallDealResult + { + [Newtonsoft.Json.JsonProperty("returns", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Returns { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasUsed { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Contracts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("txInputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection TxInputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("txOutputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection TxOutputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainInfo + { + [Newtonsoft.Json.JsonProperty("currentHeight", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public ulong CurrentHeight { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChainParams + { + [Newtonsoft.Json.JsonProperty("networkId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int NetworkId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("numZerosAtLeastInHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int NumZerosAtLeastInHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("groupNumPerBroker", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GroupNumPerBroker { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("groups", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Groups { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ChangeActiveAddress + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CompileDealResult + { + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecodeDebugPatch", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BytecodeDebugPatch { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("codeHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CodeHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("codeHashDebug", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CodeHashDebug { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public FieldsSig Fields { get; set; } = new FieldsSig(); + + [Newtonsoft.Json.JsonProperty("functions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Functions { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("constants", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Constants { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("enums", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Enums { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("warnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Warnings { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("stdInterfaceId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string StdInterfaceId { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CompileProjectResult + { + [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Contracts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("scripts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Scripts { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CompileScriptResult + { + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecodeTemplate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BytecodeTemplate { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecodeDebugPatch", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BytecodeDebugPatch { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public FieldsSig Fields { get; set; } = new FieldsSig(); + + [Newtonsoft.Json.JsonProperty("functions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Functions { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("warnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Warnings { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class CompilerOptions + { + [Newtonsoft.Json.JsonProperty("ignoreUnusedConstantsWarnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IgnoreUnusedConstantsWarnings { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("ignoreUnusedVariablesWarnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IgnoreUnusedVariablesWarnings { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("ignoreUnusedFieldsWarnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IgnoreUnusedFieldsWarnings { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("ignoreUnusedPrivateFunctionsWarnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IgnoreUnusedPrivateFunctionsWarnings { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("ignoreUpdateFieldsCheckWarnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IgnoreUpdateFieldsCheckWarnings { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("ignoreCheckExternalCallerWarnings", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IgnoreCheckExternalCallerWarnings { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Confirmed + { + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txIndex", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int TxIndex { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("chainConfirmations", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ChainConfirmations { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromGroupConfirmations", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroupConfirmations { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroupConfirmations", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroupConfirmations { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Constant + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public Args Value { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Deal + { + [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Code { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("compilerOptions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public CompilerOptions CompilerOptions { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealEvent + { + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("eventIndex", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int EventIndex { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Fields { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealEventByBlockHash + { + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("eventIndex", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int EventIndex { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Fields { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealEventByTxId + { + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string BlockHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("eventIndex", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int EventIndex { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Fields { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealEvents + { + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("nextStart", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int NextStart { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealEventsByBlockHash + { + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealEventsByTxId + { + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealOutput + { + [Newtonsoft.Json.JsonProperty("hint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Hint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("key", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Key { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("attoAlphAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string AttoAlphAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DealState + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("codeHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CodeHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("initialStateHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string InitialStateHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("immFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ImmFields { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("mutFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection MutFields { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public AssetState Asset { get; set; } = new AssetState(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DebugMessage + { + [Newtonsoft.Json.JsonProperty("contractAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ContractAddress { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DecodeUnsignedTx + { + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnsignedTx { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DecodeUnsignedTxResult + { + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public UnsignedTx UnsignedTx { get; set; } = new UnsignedTx(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Terminus + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("attoAlphAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string AttoAlphAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Tokens { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockTime", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long LockTime { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Message { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class DiscoveryAction + { + [Newtonsoft.Json.JsonProperty("peers", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Peers { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Enum + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Fields { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class EnumField + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public Args Value { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class EventSig + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fieldNames", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection FieldNames { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("fieldTypes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection FieldTypes { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FieldsSig + { + [Newtonsoft.Json.JsonProperty("names", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Names { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("types", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Types { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("isMutable", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection IsMutable { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FixedAssetOutput + { + [Newtonsoft.Json.JsonProperty("hint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Hint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("key", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Key { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("attoAlphAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string AttoAlphAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Tokens { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("lockTime", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long LockTime { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class FunctionSig + { + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("usePreapprovedAssets", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool UsePreapprovedAssets { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("useAssetsInContract", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool UseAssetsInContract { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("isPublic", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IsPublic { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("paramNames", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ParamNames { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("paramTypes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ParamTypes { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("paramIsMutable", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ParamIsMutable { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("returnTypes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ReturnTypes { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Group + { + [Newtonsoft.Json.JsonProperty("group", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Group1 { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class HashesAtHeight + { + [Newtonsoft.Json.JsonProperty("headers", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Headers { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class InterCliquePeerInfo + { + [Newtonsoft.Json.JsonProperty("cliqueId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CliqueId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("brokerId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int BrokerId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("groupNumPerBroker", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GroupNumPerBroker { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public Address2 Address { get; set; } = new Address2(); + + [Newtonsoft.Json.JsonProperty("isSynced", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IsSynced { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("clientVersion", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ClientVersion { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class InternalServerError + { + [Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Detail { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class MemPooled + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class MempoolSettlements + { + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("transactions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Transactions { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class MinerAddresses + { + [Newtonsoft.Json.JsonProperty("addresses", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Addresses { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class MinerAddressesInfo + { + [Newtonsoft.Json.JsonProperty("addresses", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Addresses { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class MultipleCallDeal + { + [Newtonsoft.Json.JsonProperty("calls", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Calls { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class MultipleCallDealResult + { + [Newtonsoft.Json.JsonProperty("results", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Results { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class NodeInfo + { + [Newtonsoft.Json.JsonProperty("buildInfo", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public BuildInfo BuildInfo { get; set; } = new BuildInfo(); + + [Newtonsoft.Json.JsonProperty("upnp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Upnp { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("externalAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public ExternalAddress ExternalAddress { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class NodeVersion + { + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class NotFound + { + [Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Detail { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("resource", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Resource { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class OutputRef + { + [Newtonsoft.Json.JsonProperty("hint", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Hint { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("key", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Key { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PeerAddress + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("restPort", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int RestPort { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("wsPort", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int WsPort { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("minerApiPort", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int MinerApiPort { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Status + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public string Type { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public int Value { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class PeerMisbehavior + { + [Newtonsoft.Json.JsonProperty("peer", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Peer { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public Status Status { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class InfoHashrate + { + [Newtonsoft.Json.JsonProperty("hashrate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public string Hashrate { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class InfoDifficulty + { + [Newtonsoft.Json.JsonProperty("difficulty", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public double Difficulty { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Penalty + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Value { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Project + { + [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Code { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("compilerOptions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public CompilerOptions CompilerOptions { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class RevealMnemonic + { + [Newtonsoft.Json.JsonProperty("password", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Password { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class RevealMnemonicResult + { + [Newtonsoft.Json.JsonProperty("mnemonic", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Mnemonic { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Script + { + [Newtonsoft.Json.JsonProperty("code", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Code { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("compilerOptions", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public CompilerOptions CompilerOptions { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SelfClique + { + [Newtonsoft.Json.JsonProperty("cliqueId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CliqueId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("nodes", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Nodes { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("selfReady", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool SelfReady { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("synced", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Synced { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ServiceUnavailable + { + [Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Detail { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Sign + { + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SignResult + { + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SubmitMultisig + { + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnsignedTx { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("signatures", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Signatures { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SubmitSettlement + { + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnsignedTx { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SubmitTxResult + { + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Sweep + { + [Newtonsoft.Json.JsonProperty("toAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ToAddress { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockTime", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long LockTime { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("utxosLimit", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int UtxosLimit { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("targetBlockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TargetBlockHash { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SweepAddressSettlement + { + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("unsignedTx", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string UnsignedTx { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TestDeal + { + [Newtonsoft.Json.JsonProperty("group", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Group { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("blockHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string BlockHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("blockTimeStamp", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long BlockTimeStamp { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("bytecode", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Bytecode { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("initialImmFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection InitialImmFields { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("initialMutFields", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection InitialMutFields { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("initialAsset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public AssetState InitialAsset { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("methodIndex", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int MethodIndex { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("args", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Args { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("existingContracts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection ExistingContracts { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("inputAssets", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection InputAssets { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TestDealResult + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("codeHash", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string CodeHash { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("returns", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Returns { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("gasUsed", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasUsed { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("contracts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Contracts { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("txInputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection TxInputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("txOutputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection TxOutputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("events", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Events { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("debugMessages", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection DebugMessages { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TestInputAsset + { + [Newtonsoft.Json.JsonProperty("address", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Address { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("asset", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public AssetState Asset { get; set; } = new AssetState(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Token + { + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Settlement + { + [Newtonsoft.Json.JsonProperty("unsigned", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public UnsignedTx Unsigned { get; set; } = new UnsignedTx(); + + [Newtonsoft.Json.JsonProperty("scriptExecutionOk", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool ScriptExecutionOk { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("contractInputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ContractInputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("generatedOutputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection GeneratedOutputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("inputSignatures", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection InputSignatures { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("scriptSignatures", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ScriptSignatures { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class SettlementTemplate + { + [Newtonsoft.Json.JsonProperty("unsigned", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public UnsignedTx Unsigned { get; set; } = new UnsignedTx(); + + [Newtonsoft.Json.JsonProperty("inputSignatures", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection InputSignatures { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("scriptSignatures", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection ScriptSignatures { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Transfer + { + [Newtonsoft.Json.JsonProperty("destinations", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Destinations { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("gas", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Gas { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("utxosLimit", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int UtxosLimit { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TransferResult + { + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("fromGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int FromGroup { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("toGroup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int ToGroup { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TransferResults + { + [Newtonsoft.Json.JsonProperty("results", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Results { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class TxNotFound + { + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UTXO + { + [Newtonsoft.Json.JsonProperty("ref", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public OutputRef Ref { get; set; } = new OutputRef(); + + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Amount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("tokens", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Tokens { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("lockTime", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public long LockTime { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("additionalData", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string AdditionalData { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UTXOs + { + [Newtonsoft.Json.JsonProperty("utxos", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Utxos { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("warning", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Warning { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Unauthorized + { + [Newtonsoft.Json.JsonProperty("detail", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Detail { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Unban + { + [Newtonsoft.Json.JsonProperty("peers", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Peers { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Unreachable + { + [Newtonsoft.Json.JsonProperty("peers", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Peers { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class UnsignedTx + { + [Newtonsoft.Json.JsonProperty("txId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string TxId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("version", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Version { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("networkId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int NetworkId { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("scriptOpt", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ScriptOpt { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int GasAmount { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("gasPrice", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string GasPrice { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("inputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Inputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("fixedOutputs", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection FixedOutputs { get; set; } = new System.Collections.ObjectModel.Collection(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Val + { + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ValArray + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] + public System.Collections.Generic.ICollection Value { get; set; } = new System.Collections.ObjectModel.Collection(); + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ValBool + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Value { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ValByteVec + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ValI256 + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ValU256 + { + [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Value { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class VerifySignature + { + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Data { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("signature", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Signature { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("publicKey", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string PublicKey { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WalletCreation + { + [Newtonsoft.Json.JsonProperty("password", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Password { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("walletName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletName { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("isMiner", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IsMiner { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("mnemonicPassphrase", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MnemonicPassphrase { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("mnemonicSize", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int MnemonicSize { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WalletCreationResult + { + [Newtonsoft.Json.JsonProperty("walletName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletName { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("mnemonic", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Mnemonic { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WalletDeletion + { + [Newtonsoft.Json.JsonProperty("password", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Password { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WalletRestore + { + [Newtonsoft.Json.JsonProperty("password", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Password { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("mnemonic", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Mnemonic { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("walletName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletName { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("isMiner", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IsMiner { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("mnemonicPassphrase", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MnemonicPassphrase { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WalletRestoreResult + { + [Newtonsoft.Json.JsonProperty("walletName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletName { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WalletStatus + { + [Newtonsoft.Json.JsonProperty("walletName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string WalletName { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("locked", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool Locked { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class WalletUnlock + { + [Newtonsoft.Json.JsonProperty("password", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Password { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("mnemonicPassphrase", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string MnemonicPassphrase { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Address + { + [Newtonsoft.Json.JsonProperty("addr", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Addr { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("port", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Port { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class Address2 + { + [Newtonsoft.Json.JsonProperty("addr", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Addr { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("port", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Port { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class ExternalAddress + { + [Newtonsoft.Json.JsonProperty("addr", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Addr { get; set; } = default!; + + [Newtonsoft.Json.JsonProperty("port", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int Port { get; set; } = default!; + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + } + + + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AlephiumApiException : System.Exception + { + public int StatusCode { get; private set; } + + public string? Response { get; private set; } + + public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } + + public AlephiumApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception? innerException) + : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.16.1.0 (NJsonSchema v10.7.2.0 (Newtonsoft.Json v13.0.0.0))")] + public partial class AlephiumApiException : AlephiumApiException + { + public TResult Result { get; private set; } + + public AlephiumApiException(string message, int statusCode, string? response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception? innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + } + } + +} + +#pragma warning restore 1591 +#pragma warning restore 1573 +#pragma warning restore 472 +#pragma warning restore 114 +#pragma warning restore 108 +#pragma warning restore 3016 +#pragma warning restore 8603 diff --git a/src/Miningcore/Blockchain/Alephium/RPC/alephium.nswag b/src/Miningcore/Blockchain/Alephium/RPC/alephium.nswag new file mode 100644 index 000000000..53b45f6e9 --- /dev/null +++ b/src/Miningcore/Blockchain/Alephium/RPC/alephium.nswag @@ -0,0 +1,99 @@ +{ + "runtime": "Net60", + "defaultVariables": null, + "documentGenerator": { + "fromDocument": { + "url": "https://raw.githubusercontent.com/alephium/alephium/master/api/src/main/resources/openapi.json", + "output": null, + "newLineBehavior": "Auto" + } + }, + "codeGenerators": { + "openApiToCSharpClient": { + "clientBaseClass": null, + "configurationClass": null, + "generateClientClasses": true, + "generateClientInterfaces": false, + "clientBaseInterface": null, + "injectHttpClient": true, + "disposeHttpClient": true, + "protectedMethods": [], + "generateExceptionClasses": true, + "exceptionClass": "ApiException", + "wrapDtoExceptions": true, + "useHttpClientCreationMethod": false, + "httpClientType": "System.Net.Http.HttpClient", + "useHttpRequestMessageCreationMethod": false, + "useBaseUrl": true, + "generateBaseUrlProperty": true, + "generateSyncMethods": false, + "generatePrepareRequestAndProcessResponseAsAsyncMethods": true, + "exposeJsonSerializerSettings": false, + "clientClassAccessModifier": "public", + "typeAccessModifier": "public", + "generateContractsOutput": false, + "contractsNamespace": null, + "contractsOutputFilePath": null, + "parameterDateTimeFormat": "s", + "parameterDateFormat": "yyyy-MM-dd", + "generateUpdateJsonSerializerSettingsMethod": true, + "useRequestAndResponseSerializationSettings": false, + "serializeTypeInformation": false, + "queryNullValue": "", + "className": "AlephiumClient", + "operationGenerationMode": "MultipleClientsFromOperationId", + "additionalNamespaceUsages": [], + "additionalContractNamespaceUsages": [], + "generateOptionalParameters": false, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "parameterArrayType": "System.Collections.Generic.IEnumerable", + "parameterDictionaryType": "System.Collections.Generic.IDictionary", + "responseArrayType": "System.Collections.Generic.ICollection", + "responseDictionaryType": "System.Collections.Generic.IDictionary", + "wrapResponses": false, + "wrapResponseMethods": [], + "generateResponseClasses": true, + "responseClass": "SwaggerResponse", + "namespace": "Miningcore.Blockchain.Alephium", + "requiredPropertiesMustBeDefined": false, + "dateType": "System.DateTimeOffset", + "jsonConverters": null, + "anyType": "object", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "classStyle": "Poco", + "jsonLibrary": "NewtonsoftJson", + "generateDefaultValues": true, + "generateDataAnnotations": true, + "excludedTypeNames": [], + "excludedParameterNames": [], + "handleReferences": false, + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "jsonSerializerSettingsTransformationMethod": null, + "inlineNamedArrays": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedAny": false, + "generateDtoTypes": true, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": true, + "templateDirectory": null, + "typeNameGeneratorType": null, + "propertyNameGeneratorType": null, + "enumNameGeneratorType": null, + "serviceHost": null, + "serviceSchemes": null, + "output": "AlephiumClient.cs", + "newLineBehavior": "Auto" + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Beam/BeamJob.cs b/src/Miningcore/Blockchain/Beam/BeamJob.cs index e20403e40..0bb17ec91 100644 --- a/src/Miningcore/Blockchain/Beam/BeamJob.cs +++ b/src/Miningcore/Blockchain/Beam/BeamJob.cs @@ -87,7 +87,8 @@ public class BeamJob if(isBlockCandidate) { result.IsBlockCandidate = true; - result.BlockHash = solution + nonce; + //result.BlockHash = solution + nonce; + result.BlockHash = solutionHash.ToHexString(); } return (result, null, BeamConstants.BeamRpcShareAccepted); diff --git a/src/Miningcore/Blockchain/Beam/BeamJobManager.cs b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs index a82a1d6d7..3d126759a 100644 --- a/src/Miningcore/Blockchain/Beam/BeamJobManager.cs +++ b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs @@ -69,6 +69,7 @@ public BeamJobManager( private BeamPoolConfigExtra extraPoolConfig; public ulong? Forkheight; public ulong? Forkheight2; + protected string PoolNoncePrefix; private BeamCoinTemplate coin; protected IObservable BeamSubscribeStratumApiSocketClient(CancellationToken ct, DaemonEndpointConfig endPoint, @@ -91,14 +92,14 @@ protected IObservable BeamSubscribeStratumApiSocketClient(CancellationTo try { int port = endPoint.Port; - IPHostEntry ipHostEntry = await Dns.GetHostEntryAsync(endPoint.Host); - IPEndPoint ipEndPoint = new IPEndPoint(ipHostEntry.AddressList[1], port); + IPAddress[] iPAddress = await Dns.GetHostAddressesAsync(endPoint.Host, AddressFamily.InterNetwork, cts.Token); + IPEndPoint ipEndPoint = new IPEndPoint(iPAddress.First(), port); using Socket client = new(SocketType.Stream, ProtocolType.Tcp); client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1); client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1); client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); - logger.Debug(() => $"Establishing socket connection with `{ipHostEntry.AddressList[1]}:{port}`"); + logger.Debug(() => $"Establishing socket connection with `{iPAddress.First().ToString()}:{port}`"); await client.ConnectAsync(ipEndPoint, cts.Token); if (client.Connected) logger.Debug(() => $"Socket connection succesffuly established"); @@ -138,6 +139,8 @@ protected IObservable BeamSubscribeStratumApiSocketClient(CancellationTo if (!line.Contains("job")) { var loginResponse = JsonConvert.DeserializeObject(line); + logger.Debug(() => $"Updating pool Nonceprefix"); + PoolNoncePrefix = loginResponse?.Nonceprefix; logger.Debug(() => $"Updating Forkheight values"); Forkheight = (loginResponse?.Forkheight > 0) ? loginResponse.Forkheight : null; Forkheight2 = (loginResponse?.Forkheight2 > 0) ? loginResponse.Forkheight2 : null; @@ -212,7 +215,7 @@ protected async Task UpdateJob(CancellationToken ct, string via = null, st var job = currentJob; - var isNew = job == null || (blockTemplate != null && blockTemplate.Input != null && blockTemplate.Height > job.BlockTemplate?.Height); + var isNew = job == null || (blockTemplate != null && blockTemplate.Input != null && (blockTemplate.JobId != job.BlockTemplate?.JobId || blockTemplate.Height > job.BlockTemplate?.Height)); if(isNew) { @@ -240,8 +243,11 @@ protected async Task UpdateJob(CancellationToken ct, string via = null, st logger.Info(() => $"Detected new block {blockTemplate.Height}"); // update stats - BlockchainStats.LastNetworkBlockTime = clock.Now; - BlockchainStats.BlockHeight = blockTemplate.Height; + if (blockTemplate.Height > BlockchainStats.BlockHeight) + { + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = blockTemplate.Height; + } BlockchainStats.NetworkDifficulty = (double) job.BlockTemplate.Difficulty; } @@ -335,7 +341,7 @@ private async Task UpdateNetworkStatsAsync(CancellationToken ct) } } - public object[] GetSubscriberData(StratumConnection worker) + public string GetSubscriberData(StratumConnection worker) { Contract.RequiresNonNull(worker); @@ -343,14 +349,8 @@ public object[] GetSubscriberData(StratumConnection worker) // assign unique ExtraNonce1 to worker (miner) context.ExtraNonce1 = extraNonceProvider.Next(); - - // setup response data - var responseData = new object[] - { - context.ExtraNonce1 - }; - - return responseData; + + return context.ExtraNonce1; } private void SubmitBlock(CancellationToken ct, DaemonEndpointConfig endPoint, object request, Share share, object payload = null, JsonSerializerSettings payloadJsonSerializerSettings = null) @@ -369,23 +369,23 @@ private void SubmitBlock(CancellationToken ct, DaemonEndpointConfig endPoint, ob try { int port = endPoint.Port; - IPHostEntry ipHostEntry = await Dns.GetHostEntryAsync(endPoint.Host); - IPEndPoint ipEndPoint = new IPEndPoint(ipHostEntry.AddressList[1], port); + IPAddress[] iPAddress = await Dns.GetHostAddressesAsync(endPoint.Host, AddressFamily.InterNetwork, cts.Token); + IPEndPoint ipEndPoint = new IPEndPoint(iPAddress.First(), port); using Socket client = new(SocketType.Stream, ProtocolType.Tcp); //client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1); client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1); client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); - logger.Debug(() => $"[Submit Block] - Establishing socket connection with `{ipHostEntry.AddressList[1]}:{port}`"); + logger.Debug(() => $"[Submit Block] - Establishing socket connection with `{iPAddress.First().ToString()}:{port}`"); await client.ConnectAsync(ipEndPoint, cts.Token); if (client.Connected) - logger.Debug(() => $"[Submit Block] - Socket connection succesffuly established"); + logger.Debug(() => $"[Submitting block] - Socket connection succesffuly established"); using NetworkStream stream = new NetworkStream(client, false); string json = JsonConvert.SerializeObject(request, payloadJsonSerializerSettings); byte[] requestData = Encoding.UTF8.GetBytes($"{json}\r\n"); - logger.Debug(() => $"[Submit Block] - Sending request `{json}`"); + logger.Debug(() => $"[Submitting block] - Sending request `{json}`"); // send await stream.WriteAsync(requestData, 0, requestData.Length, cts.Token); @@ -548,7 +548,7 @@ public async Task ValidateAddressAsync(string address, CancellationToken c var shareSubmitRequest = new BeamSubmitRequest { Id = JobId, - Nonce = nonce, + Nonce = (!string.IsNullOrEmpty(PoolNoncePrefix)) ? PoolNoncePrefix : nonce, Output = solution }; @@ -557,8 +557,9 @@ public async Task ValidateAddressAsync(string address, CancellationToken c logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {context.Miner}"); // persist the coinbase transaction-hash to allow the payment processor - // Be aware for BEAM, the block verification and confirmation is performed with `share.BlockHash` - share.TransactionConfirmationData = share.BlockHeight.ToString(); + // Be aware for BEAM, the block verification and confirmation must be performed with `share.BlockHash` if the socket did not return a `Nonceprefix` after login + share.TransactionConfirmationData = (!string.IsNullOrEmpty(PoolNoncePrefix)) ? share.BlockHash : share.BlockHeight.ToString(); + share.BlockHash = (!string.IsNullOrEmpty(PoolNoncePrefix)) ? null : solution + nonce; OnBlockFound(); } @@ -578,7 +579,11 @@ protected override void ConfigureDaemons() explorerRestClient = new SimpleRestClient(httpClientFactory, "http://" + explorerDaemonEndpoints.First().Host.ToString() + ":" + explorerDaemonEndpoints.First().Port.ToString() + "/"); logger.Debug(() => $"`beam-node-explorer` URL: http://{explorerDaemonEndpoints.First().Host.ToString()}:{explorerDaemonEndpoints.First().Port.ToString()}/"); - walletRpc = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + walletRpc = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + } } protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) @@ -586,9 +591,15 @@ protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) try { var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); - var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct); - return responseWalletRpc.Error == null; + return responseWalletRpc.Error == null; + } + + return true; } catch(Exception) @@ -627,29 +638,35 @@ protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) { var responseExplorerRestClient = await explorerRestClient.Get(BeamConstants.ExplorerDaemonRpcStatusLocation, ct); - var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct); - - if(responseWalletRpc.Error != null) + // It's only possible to know if the node is synchronized when using both daemons + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { - logger.Debug(() => $"`wallet-api` daemon response: {responseWalletRpc.Error.Message} (Code {responseWalletRpc.Error.Code})"); - } - - else - { - var isSynched = (responseExplorerRestClient.Height == responseWalletRpc.Response.Height); + var responseWalletRpc = await walletRpc.ExecuteAsync(logger, BeamWalletCommands.GetBalance, ct); - if(isSynched) + if(responseWalletRpc.Error != null) { - logger.Info(() => "All daemons synched with blockchain"); - break; + logger.Debug(() => $"`wallet-api` daemon response: {responseWalletRpc.Error.Message} (Code {responseWalletRpc.Error.Code})"); } - if(!syncPendingNotificationShown) + else { - logger.Info(() => "Daemon is still syncing with network. Manager will be started once synced."); - syncPendingNotificationShown = true; + var isSynched = (responseExplorerRestClient.Height == responseWalletRpc.Response.Height); + + 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; + } } } + else + break; await ShowDaemonSyncProgressAsync(ct); } while(await timer.WaitForNextTickAsync(ct)); diff --git a/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs b/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs index 520722d40..8820ba7c3 100644 --- a/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs @@ -246,9 +246,12 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, result.Add(block); messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + // Be aware for BEAM, the block verification and confirmation must be performed with `block.Hash` if the socket did not return a `Nonceprefix` after login + bool IsOrphaned = (!string.IsNullOrEmpty(block.Hash)) ? (!string.IsNullOrEmpty(rpcResult.Response?.Pow) && rpcResult.Response?.Pow.Contains(block.Hash) == false) : (!string.IsNullOrEmpty(rpcResult.Response?.BlockHash) && rpcResult.Response?.BlockHash == block.TransactionConfirmationData); // orphaned? - if(!string.IsNullOrEmpty(rpcResult.Response?.Pow) && rpcResult.Response?.Pow.Contains(block.Hash) == false) + if(IsOrphaned) { block.Hash = null; block.Status = BlockStatus.Orphaned; @@ -261,8 +264,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, // matured and spendable? if((lastBlock.Height - block.BlockHeight) >= BeamConstants.PayoutMinBlockConfirmations) { - block.TransactionConfirmationData = rpcResult.Response?.BlockHash; - block.Hash = rpcResult.Response?.BlockHash; + block.Hash = (!string.IsNullOrEmpty(block.Hash)) ? rpcResult.Response?.BlockHash : null; block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; block.Reward = GetBaseBlockReward(block.BlockHeight); // base reward diff --git a/src/Miningcore/Blockchain/Beam/BeamPool.cs b/src/Miningcore/Blockchain/Beam/BeamPool.cs index 2ba6d2759..59844017b 100644 --- a/src/Miningcore/Blockchain/Beam/BeamPool.cs +++ b/src/Miningcore/Blockchain/Beam/BeamPool.cs @@ -58,6 +58,8 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped $"[{connection.ConnectionId}] Setting static difficulty of {staticDiff.Value}"); } - var data = new object[] - { - connection.ConnectionId, - } - .Concat(manager.GetSubscriberData(connection)) - .ToArray(); - // setup worker context context.IsSubscribed = true; - context.UserAgent = request?.UserAgent; // response var loginResponse = new BeamLoginResponse { Code = BeamConstants.BeamRpcLoginSuccess, Description = "Login successful", - Nonceprefix = connection.ConnectionId, + Nonceprefix = manager.GetSubscriberData(connection), Forkheight = manager?.Forkheight, Forkheight2 = manager?.Forkheight2 }; @@ -134,7 +128,8 @@ private async Task OnLoginAsync(StratumConnection connection, Timestamped ForEachMinerAsync(async (connection, ct) => Id = (string) currentJobParams[0], Height = (ulong) currentJobParams[1], Difficulty = BeamUtils.PackedDifficulty(context.Difficulty), - Input = (string) currentJobParams[4] + Input = (string) currentJobParams[4], + Nonceprefix = context.ExtraNonce1 }; // respond @@ -469,13 +465,15 @@ protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, if(connection.Context.ApplyPendingDifficulty()) { var currentJobParams = manager.GetJobParamsForStratum(); + var context = connection.ContextAs(); // response var jobResponse = new BeamJobResponse { Id = (string) currentJobParams[0], Height = (ulong) currentJobParams[1], - Difficulty = BeamUtils.PackedDifficulty(connection.Context.Difficulty), - Input = (string) currentJobParams[4] + Difficulty = BeamUtils.PackedDifficulty(context.Difficulty), + Input = (string) currentJobParams[4], + Nonceprefix = context.ExtraNonce1 }; // respond diff --git a/src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs index 9c8647c08..fcb9dc087 100644 --- a/src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs +++ b/src/Miningcore/Blockchain/Beam/StratumResponses/BeamJobResponse.cs @@ -16,6 +16,9 @@ public class BeamJobResponse : BeamResponseBase [JsonProperty("input")] public string Input { get; set; } + [JsonProperty("nonceprefix", NullValueHandling = NullValueHandling.Ignore)] + public string Nonceprefix { get; set; } = null; + [JsonProperty("method")] public string Method { get; set; } = "job"; } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs index 0db3cd3bd..327698fdf 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinConstants.cs @@ -19,6 +19,11 @@ public enum BitcoinAddressType /// Bitcoin Cash /// BCash, + + /// + /// Litecoin + /// + Litecoin, } public enum BitcoinTransactionCategory diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs index 0557ac076..c695cb07d 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJob.cs @@ -410,6 +410,18 @@ protected virtual byte[] SerializeBlock(byte[] header, byte[] coinbase) if(isPoS) bs.ReadWrite((byte) 0); + // if pool supports MWEB, we have to append the MWEB data to the block + // https://github.com/litecoin-project/litecoin/blob/0.21/doc/mweb/mining-changes.md + if(coin.HasMWEB) + { + var separator = new byte[] { 0x01 }; + var mweb = BlockTemplate.Extra.SafeExtensionDataAs(); + var mwebRaw = mweb.Mweb.HexToByteArray(); + + bs.ReadWrite(ref separator); + bs.ReadWrite(ref mwebRaw); + } + return stream.ToArray(); } } diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs index b8df94e37..08c84896b 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManager.cs @@ -13,6 +13,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NLog; +using Org.BouncyCastle.Crypto.Parameters; namespace Miningcore.Blockchain.Bitcoin; @@ -32,6 +33,17 @@ public BitcoinJobManager( protected override object[] GetBlockTemplateParams() { var result = base.GetBlockTemplateParams(); + + if(coin.HasMWEB) + { + result = new object[] + { + new + { + rules = new[] {"segwit", "mweb"}, + } + }; + } if(coin.BlockTemplateRpcExtraParams != null) { @@ -43,6 +55,39 @@ protected override object[] GetBlockTemplateParams() return result; } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + var syncPendingNotificationShown = false; + + do + { + var response = await rpc.ExecuteAsync(logger, + BitcoinCommands.GetBlockTemplate, ct, GetBlockTemplateParams()); + + var isSynched = response.Error == null; + + if(isSynched) + { + logger.Info(() => "All daemons synched with blockchain"); + break; + } + else + { + logger.Debug(() => $"Daemon reports error: {response.Error?.Message}"); + } + + 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 async Task> GetBlockTemplateAsync(CancellationToken ct) { diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index e48a86d5e..085fa11f1 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -381,7 +381,12 @@ protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) var response = await rpc.ExecuteAsync(logger, BitcoinCommands.GetBlockchainInfo, ct); - return response.Error == null; + if(response.Error != null) + { + logger.Error(() => $"Daemon reports: {response.Error.Message}"); + return false; + } + return true; } protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) @@ -534,6 +539,9 @@ protected virtual IDestination AddressToDestination(string address, BitcoinAddre case BitcoinAddressType.BCash: return BitcoinUtils.BCashAddressToDestination(poolConfig.Address, network); + case BitcoinAddressType.Litecoin: + return BitcoinUtils.LitecoinAddressToDestination(poolConfig.Address, network); + default: return BitcoinUtils.AddressToDestination(poolConfig.Address, network); } diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs index ea9fa0dd7..9a41a1bab 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinUtils.cs @@ -41,4 +41,16 @@ public static IDestination BCashAddressToDestination(string address, Network exp var trashAddress = bcash.Parse(address); return trashAddress.ScriptPubKey.GetDestinationAddress(bcash); } + + public static IDestination LitecoinAddressToDestination(string address, Network expectedNetwork) + { + var litecoin = NBitcoin.Altcoins.Litecoin.Instance.GetNetwork(expectedNetwork.ChainName); + var encoder = litecoin.GetBech32Encoder(Bech32Type.WITNESS_PUBKEY_ADDRESS, true); + + var decoded = encoder.Decode(address, out var witVersion); + var result = new WitKeyId(decoded); + + Debug.Assert(result.GetAddress(litecoin).ToString() == address); + return result; + } } diff --git a/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Mweb.cs b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Mweb.cs new file mode 100644 index 000000000..b5b2049fd --- /dev/null +++ b/src/Miningcore/Blockchain/Bitcoin/DaemonResponses/Mweb.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Bitcoin.DaemonResponses; + +public class MwebBlockTemplateExtra +{ + public string Mweb { get; set; } +} diff --git a/src/Miningcore/Blockchain/Equihash/DaemonRequests/SendCurrency.cs b/src/Miningcore/Blockchain/Equihash/DaemonRequests/SendCurrency.cs new file mode 100644 index 000000000..3d7e6507d --- /dev/null +++ b/src/Miningcore/Blockchain/Equihash/DaemonRequests/SendCurrency.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Equihash.DaemonRequests; + +public class SendCurrencyOutputs +{ + [JsonProperty("currency", NullValueHandling = NullValueHandling.Ignore)] + public string Currency { get; set; } + + public decimal Amount { get; set; } + public string Address { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs b/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs index 0c31d25b1..eb7493b7d 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashConstants.cs @@ -35,6 +35,14 @@ public static class EquihashCommands public const string ZGetListAddresses = "z_listaddresses"; public const string ZValidateAddress = "z_validateaddress"; public const string ZShieldCoinbase = "z_shieldcoinbase"; + + /// + /// Some projects like Veruscoin does not require shielding before being able to spend coins. + /// They can also sends coins from a t-address to t-addresses and z-addresses + /// Returns an operation-id. You use the operationid value with z_getoperationstatus and + /// z_getoperationresult to obtain the result of sending funds, which if successful, will be a txid. + /// + public const string SendCurrency = "sendcurrency"; /// /// Returns an operationid. You use the operationid value with z_getoperationstatus and diff --git a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs index 129d798d4..e521b0bd8 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashJobManager.cs @@ -203,25 +203,20 @@ public override async Task ValidateAddressAsync(string address, Cancellati if(string.IsNullOrEmpty(address)) return false; - switch(coin.Symbol) + // handle t-addr + if(await base.ValidateAddressAsync(address, ct)) + return true; + + if(!coin.UseBitcoinPayoutHandler) { - case "VRSC": - // handle t-addr - if(await base.ValidateAddressAsync(address, ct)) - return true; - - return false; - default: - // handle t-addr - if(await base.ValidateAddressAsync(address, ct)) - return true; - - // handle z-addr - var result = await rpc.ExecuteAsync(logger, - EquihashCommands.ZValidateAddress, ct, new[] { address }); - - return result.Response is {IsValid: true}; + // handle z-addr + var result = await rpc.ExecuteAsync(logger, + EquihashCommands.ZValidateAddress, ct, new[] { address }); + + return result.Response is {IsValid: true}; } + + return false; } public object[] GetSubscriberData(StratumConnection worker) diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs b/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs index 0523d61be..8ac76e031 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPayoutHandler.cs @@ -39,6 +39,7 @@ public EquihashPayoutHandler( protected EquihashPoolConfigExtra poolExtraConfig; protected bool supportsNativeShielding; + protected bool supportsSendCurrency; protected Network network; protected EquihashCoinTemplate.EquihashNetworkParams chainConfig; protected override string LogCategory => "Equihash Payout Handler"; @@ -63,9 +64,30 @@ public override async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, Cance // detect z_shieldcoinbase support var response = await rpcClient.ExecuteAsync(logger, EquihashCommands.ZShieldCoinbase, ct); supportsNativeShielding = response.Error.Code != (int) BitcoinRPCErrorCode.RPC_METHOD_NOT_FOUND; + + // detect sendcurrency support + var responseSendCurrency = await rpcClient.ExecuteAsync(logger, EquihashCommands.SendCurrency, ct); + supportsSendCurrency = responseSendCurrency.Error.Code != (int) BitcoinRPCErrorCode.RPC_METHOD_NOT_FOUND; } public override async Task PayoutAsync(IMiningPool pool, Balance[] balances, CancellationToken ct) + { + Contract.RequiresNonNull(balances); + + // Some projects like Veruscoin does not require shielding before being able to spend coins. + // They can also sends coins from a t-address to t-addresses and z-addresses + if(supportsSendCurrency) + await PayoutSendCurrencyAsync(pool, balances, ct); + else + await PayoutZSendManyAsync(pool, balances, ct); + + // lock wallet + logger.Info(() => $"[{LogCategory}] Locking wallet"); + + await rpcClient.ExecuteAsync(logger, BitcoinCommands.WalletLock, ct); + } + + private async Task PayoutZSendManyAsync(IMiningPool pool, Balance[] balances, CancellationToken ct) { Contract.RequiresNonNull(balances); @@ -133,7 +155,7 @@ public override async Task PayoutAsync(IMiningPool pool, Balance[] balances, Can // check result if(string.IsNullOrEmpty(operationId)) - logger.Error(() => $"[{LogCategory}] {EquihashCommands.ZSendMany} did not return a operation id!"); + logger.Error(() => $"[{LogCategory}] {EquihashCommands.ZSendMany} did not return an operation id!"); else { logger.Info(() => $"[{LogCategory}] Tracking payment operation id: {operationId}"); @@ -229,11 +251,155 @@ public override async Task PayoutAsync(IMiningPool pool, Balance[] balances, Can } } } + } + + private async Task PayoutSendCurrencyAsync(IMiningPool pool, Balance[] balances, CancellationToken ct) + { + Contract.RequiresNonNull(balances); + + var coin = poolConfig.Template.As(); + + logger.Info(() => $"[{LogCategory}] Shielding ZCash Coinbase funds is not required"); + + // send in batches with no more than 50 recipients to avoid running into tx size limits + var pageSize = 50; + var pageCount = (int) Math.Ceiling(balances.Length / (double) pageSize); - // lock wallet - logger.Info(() => $"[{LogCategory}] Locking wallet"); + for(var i = 0; i < pageCount; i++) + { + var didUnlockWallet = false; - await rpcClient.ExecuteAsync(logger, BitcoinCommands.WalletLock, ct); + // get a page full of balances + var page = balances + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + // build args + var amounts = page + .Where(x => x.Amount > 0) + .Select(x => new SendCurrencyOutputs { Amount = Math.Round(x.Amount, 8), Address = x.Address }) + .ToArray(); + + if(amounts.Length == 0) + return; + + var pageAmount = amounts.Sum(x => x.Amount); + + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(pageAmount)} to {page.Length} addresses"); + + var args = new object[] + { + "*", // source: wildcard "*" means any addresses own by "wallet.dat" + amounts, // addresses and associated amounts + }; + + // send command + trySendCurrencyTransfer: + var response = await rpcClient.ExecuteAsync(logger, EquihashCommands.SendCurrency, ct, args); + + if(response.Error == null) + { + var operationId = response.Response; + + // check result + if(string.IsNullOrEmpty(operationId)) + logger.Error(() => $"[{LogCategory}] {EquihashCommands.SendCurrency} did not return an operation id!"); + else + { + logger.Info(() => $"[{LogCategory}] Tracking payment operation id: {operationId}"); + + var continueWaiting = true; + + while(continueWaiting) + { + var operationResultResponse = await rpcClient.ExecuteAsync(logger, + EquihashCommands.ZGetOperationResult, ct, new object[] { new object[] { operationId } }); + + if(operationResultResponse.Error == null && + operationResultResponse.Response?.Any(x => x.OperationId == operationId) == true) + { + var operationResult = operationResultResponse.Response.First(x => x.OperationId == operationId); + + if(!Enum.TryParse(operationResult.Status, true, out ZOperationStatus status)) + { + logger.Error(() => $"Unrecognized operation status: {operationResult.Status}"); + break; + } + + switch(status) + { + case ZOperationStatus.Success: + var txId = operationResult.Result?.Value("txid") ?? string.Empty; + logger.Info(() => $"[{LogCategory}] {EquihashCommands.SendCurrency} completed with transaction id: {txId}"); + + await PersistPaymentsAsync(page, txId); + NotifyPayoutSuccess(poolConfig.Id, page, new[] { txId }, null); + + continueWaiting = false; + continue; + + case ZOperationStatus.Cancelled: + case ZOperationStatus.Failed: + logger.Error(() => $"{EquihashCommands.SendCurrency} failed: {operationResult.Error.Message} code {operationResult.Error.Code}"); + NotifyPayoutFailure(poolConfig.Id, page, $"{EquihashCommands.SendCurrency} failed: {operationResult.Error.Message} code {operationResult.Error.Code}", null); + + continueWaiting = false; + continue; + } + } + + logger.Info(() => $"[{LogCategory}] Waiting for completion: {operationId}"); + + await Task.Delay(TimeSpan.FromSeconds(10), ct); + } + } + } + + else + { + if(response.Error.Code == (int) BitcoinRPCErrorCode.RPC_WALLET_UNLOCK_NEEDED && !didUnlockWallet) + { + if(!string.IsNullOrEmpty(extraPoolPaymentProcessingConfig?.WalletPassword)) + { + logger.Info(() => $"[{LogCategory}] Unlocking wallet"); + + var unlockResponse = await rpcClient.ExecuteAsync(logger, BitcoinCommands.WalletPassphrase, ct, new[] + { + extraPoolPaymentProcessingConfig.WalletPassword, + (object) 5 // unlock for N seconds + }); + + if(unlockResponse.Error == null) + { + didUnlockWallet = true; + goto trySendCurrencyTransfer; + } + + else + { + logger.Error(() => $"[{LogCategory}] {BitcoinCommands.WalletPassphrase} returned error: {response.Error.Message} code {response.Error.Code}"); + NotifyPayoutFailure(poolConfig.Id, page, $"{BitcoinCommands.WalletPassphrase} returned error: {response.Error.Message} code {response.Error.Code}", null); + break; + } + } + + else + { + logger.Error(() => $"[{LogCategory}] Wallet is locked but walletPassword was not configured. Unable to send funds."); + NotifyPayoutFailure(poolConfig.Id, page, "Wallet is locked but walletPassword was not configured. Unable to send funds.", null); + break; + } + } + + else + { + logger.Error(() => $"[{LogCategory}] {EquihashCommands.SendCurrency} returned error: {response.Error.Message} code {response.Error.Code}"); + + NotifyPayoutFailure(poolConfig.Id, page, $"{EquihashCommands.SendCurrency} returned error: {response.Error.Message} code {response.Error.Code}", null); + } + } + } } #endregion // IPayoutHandler diff --git a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs index 335149d76..9ff166795 100644 --- a/src/Miningcore/Blockchain/Equihash/EquihashPool.cs +++ b/src/Miningcore/Blockchain/Equihash/EquihashPool.cs @@ -121,6 +121,7 @@ protected async Task OnSubscribeAsync(StratumConnection connection, Timestamped< throw new StratumException(StratumError.MinusOne, "missing request id"); var requestParams = request.ParamsAs(); + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); var data = new object[] { @@ -129,11 +130,21 @@ protected async Task OnSubscribeAsync(StratumConnection connection, Timestamped< .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) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // setup worker context context.IsSubscribed = true; - context.UserAgent = requestParams.FirstOrDefault()?.Trim(); } protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) @@ -161,8 +172,19 @@ protected async Task OnAuthorizeAsync(StratumConnection connection, Timestamped< 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) + { + 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}"); @@ -252,7 +274,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) + { + response.Extra = new Dictionary(); + response.Extra["error"] = null; + } + + await connection.RespondAsync(response); // publish messageBus.SendMessage(share); diff --git a/src/Miningcore/Blockchain/Ergo/Configuration/ErgoPoolConfigExtra.cs b/src/Miningcore/Blockchain/Ergo/Configuration/ErgoPoolConfigExtra.cs index cf644cc53..757077fad 100644 --- a/src/Miningcore/Blockchain/Ergo/Configuration/ErgoPoolConfigExtra.cs +++ b/src/Miningcore/Blockchain/Ergo/Configuration/ErgoPoolConfigExtra.cs @@ -6,7 +6,7 @@ public class ErgoPoolConfigExtra { /// /// Maximum number of tracked jobs. - /// Default: 12 - you should increase this value if your blockrefreshinterval is higher than 300ms + /// Default: 4 - you should increase this value if your blockrefreshinterval is higher than 300ms /// public int? MaxActiveJobs { get; set; } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs index b8c9fffca..68d80993d 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs @@ -95,6 +95,19 @@ public class PinkConstants public const decimal BaseRewardInitial = 1.0m; } +// Rethereum +public class RethereumConstants +{ + public const ulong EpochLength = 32000; + public const ulong LondonHeight = 15787969; + public const decimal LondonBlockReward = 3.0m; + public const ulong ArrowGlacierHeight = 27200177; + public const decimal ArrowGlacierBlockReward = 2.0m; + public const ulong GrayGlacierHeight = 40725107; + public const decimal GrayGlacierBlockReward = 1.0m; + public const decimal BaseRewardInitial = 4.0m; +} + // UBIQ block reward distribution - // https://github.com/ubiq/UIPs/issues/16 - https://ubiqsmart.com/en/monetary-policy public class UbiqConstants @@ -125,6 +138,7 @@ public enum EthereumNetworkType Pink = 10100, OctaSpace = 800001, OctaSpaceTestnet = 800002, + Rethereum = 622277, Unknown = -1, } @@ -142,6 +156,7 @@ public enum GethChainType Pink = 10100, OctaSpace, OctaSpaceTestnet, + Rethereum, Unknown = -1, } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index c02a9e6d7..86feadaa6 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -166,7 +166,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, var gasUsed = blockHashResponse.Response.GasUsed; var burnedFee = (decimal) 0; - if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink") + if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink" || extraPoolConfig?.ChainTypeOverride == "Rethereum") burnedFee = (baseGas * gasUsed / EthereumConstants.Wei); block.Hash = blockHash; @@ -298,7 +298,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation // ensure we have 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") && + 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 == "Rethereum") && (infoResponse.Error != null || string.IsNullOrEmpty(infoResponse.Response) || infoResponse.Response.IntegralFromHex() < EthereumConstants.MinPayoutPeerCount)) { @@ -433,6 +433,16 @@ internal static decimal GetBaseBlockReward(GethChainType chainType, ulong height return OctaSpaceConstants.BaseRewardInitial; + case GethChainType.Rethereum: + if(height >= RethereumConstants.LondonHeight) + return RethereumConstants.LondonBlockReward; + if(height >= RethereumConstants.ArrowGlacierHeight) + return RethereumConstants.ArrowGlacierBlockReward; + if(height >= RethereumConstants.GrayGlacierHeight) + return RethereumConstants.GrayGlacierBlockReward; + + return RethereumConstants.BaseRewardInitial; + default: throw new Exception("Unable to determine block reward: Unsupported chain type"); } @@ -485,6 +495,10 @@ internal static decimal GetUncleReward(GethChainType chainType, ulong uheight, u if (reward < 0) reward = 0; + break; + case GethChainType.Rethereum: + reward = 0.1m; + break; default: reward *= uheight + 8 - height; diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs b/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs index bf37dfe8c..160f73251 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowJob.cs @@ -188,7 +188,7 @@ public virtual void Init(BlockTemplate blockTemplate, string jobId, Contract.RequiresNonNull(progpowHasher); Contract.Requires(!string.IsNullOrEmpty(jobId)); - this.coin = pc.Template.As(); + this.coin = pc.Template.As(); this.txVersion = coin.CoinbaseTxVersion; this.network = network; this.clock = clock; diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs b/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs index 754380782..d2581dcd7 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowJobManager.cs @@ -28,7 +28,7 @@ public ProgpowJobManager( { } - private ProgpowTemplate coin; + private ProgpowCoinTemplate coin; private async Task> GetBlockTemplateAsync(CancellationToken ct) { @@ -190,7 +190,7 @@ protected override object GetJobParamsForStratum(bool isNew) public override void Configure(PoolConfig pc, ClusterConfig cc) { - coin = pc.Template.As(); + coin = pc.Template.As(); extraPoolConfig = pc.Extra.SafeExtensionDataAs(); extraPoolPaymentProcessingConfig = pc.PaymentProcessing?.Extra?.SafeExtensionDataAs(); diff --git a/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs b/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs index 10392b257..772187cb2 100644 --- a/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs +++ b/src/Miningcore/Blockchain/Progpow/ProgpowPool.cs @@ -40,7 +40,7 @@ public ProgpowPool(IComponentContext ctx, private ProgpowJobParams currentJobParams; private long currentJobId; private ProgpowJobManager manager; - private ProgpowTemplate coin; + private ProgpowCoinTemplate coin; private string createEncodeTarget(double difficulty) { @@ -311,7 +311,7 @@ private ProgpowJobManager createProgpowExtraNonceProvider() public override void Configure(PoolConfig pc, ClusterConfig cc) { - coin = pc.Template.As(); + coin = pc.Template.As(); base.Configure(pc, cc); } diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index 5fa5568a3..b72e5ead3 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -16,26 +16,29 @@ namespace Miningcore.Configuration; public enum CoinFamily { + [EnumMember(Value = "alephium")] + Alephium, + [EnumMember(Value = "beam")] Beam, [EnumMember(Value = "bitcoin")] Bitcoin, - [EnumMember(Value = "equihash")] - Equihash, - [EnumMember(Value = "conceal")] Conceal, [EnumMember(Value = "cryptonote")] Cryptonote, + + [EnumMember(Value = "equihash")] + Equihash, + + [EnumMember(Value = "ergo")] + Ergo, [EnumMember(Value = "ethereum")] Ethereum, - - [EnumMember(Value = "ergo")] - Ergo, [EnumMember(Value = "progpow")] Progpow, @@ -136,17 +139,22 @@ public abstract partial class CoinTemplate [JsonIgnore] public static readonly Dictionary Families = new() { + {CoinFamily.Alephium, typeof(AlephiumCoinTemplate)}, {CoinFamily.Beam, typeof(BeamCoinTemplate)}, {CoinFamily.Bitcoin, typeof(BitcoinTemplate)}, - {CoinFamily.Equihash, typeof(EquihashCoinTemplate)}, {CoinFamily.Conceal, typeof(ConcealCoinTemplate)}, {CoinFamily.Cryptonote, typeof(CryptonoteCoinTemplate)}, - {CoinFamily.Ethereum, typeof(EthereumCoinTemplate)}, + {CoinFamily.Equihash, typeof(EquihashCoinTemplate)}, {CoinFamily.Ergo, typeof(ErgoCoinTemplate)}, - {CoinFamily.Progpow, typeof(ProgpowTemplate)}, + {CoinFamily.Ethereum, typeof(EthereumCoinTemplate)}, + {CoinFamily.Progpow, typeof(ProgpowCoinTemplate)}, }; } +public partial class AlephiumCoinTemplate : CoinTemplate +{ +} + public partial class BeamCoinTemplate : CoinTemplate { } @@ -214,6 +222,9 @@ public class BitcoinNetworkParams [DefaultValue(1.0d)] public double ShareMultiplier { get; set; } = 1.0d; + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool HasMWEB { get; set; } + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] public double? HashrateMultiplier { get; set; } @@ -236,115 +247,73 @@ public class BitcoinNetworkParams public string BlockSerializer { get; set; } } -public enum EquihashSubfamily +public enum ConcealSubfamily { [EnumMember(Value = "none")] None, } -public partial class EquihashCoinTemplate : CoinTemplate +public partial class ConcealCoinTemplate : CoinTemplate { - public partial class EquihashNetworkParams - { - public string Diff1 { get; set; } - - public int SolutionSize { get; set; } = 1344; - public int SolutionPreambleSize { get; set; } = 3; - public JObject Solver { get; set; } - public string CoinbaseTxNetwork { get; set; } - - public bool PayFoundersReward { get; set; } - public bool PayFundingStream { get; set; } - - // zencash fonder reward - public bool vOuts { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public decimal vPercentFoundersReward { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string vTreasuryRewardAddress { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public decimal vPercentTreasuryReward { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string vSecureNodesRewardAddress { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public decimal percentSecureNodesReward { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string vSuperNodesRewardAddress { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public decimal percentSuperNodesReward { get; set; } - - // zencash founder reward - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public decimal PercentFoundersReward { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string[] FoundersRewardAddresses { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public ulong FoundersRewardSubsidySlowStartInterval { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public ulong FoundersRewardSubsidyHalvingInterval { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public decimal PercentTreasuryReward { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public ulong TreasuryRewardStartBlockHeight { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string[] TreasuryRewardAddresses { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public double TreasuryRewardAddressChangeInterval { get; set; } - - // ZCash "Overwinter" - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public uint? OverwinterActivationHeight { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public uint? OverwinterTxVersion { get; set; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public uint? OverwinterTxVersionGroupId { get; set; } + [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(ConcealSubfamily.None)] + [JsonConverter(typeof(StringEnumConverter), true)] + public ConcealSubfamily Subfamily { get; set; } - // ZCash "Sapling" - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public uint? SaplingActivationHeight { get; set; } + /// + /// Broader Cryptonight hash family + /// + [JsonConverter(typeof(StringEnumConverter), true)] + [JsonProperty(Order = -5)] + public CryptonightHashType Hash { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public uint? SaplingTxVersion { get; set; } + /// + /// Set to 0 for automatic selection from blobtemplate + /// + [JsonProperty(Order = -4, DefaultValueHandling = DefaultValueHandling.Include)] + public int HashVariant { get; set; } + + /// + /// Conceal network hashrate = `Difficulty / DifficultyTarget` + /// See: parameter -> DIFFICULTY_TARGET in src/CryptoNoteConfig.h + /// + public ulong DifficultyTarget { get; set; } + + /// + /// Smallest unit for Blockreward formatting + /// + public decimal SmallestUnit { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public uint? SaplingTxVersionGroupId { get; set; } - } + /// + /// Prefix of a valid address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h + /// + public ulong AddressPrefix { get; set; } - [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - [DefaultValue(EquihashSubfamily.None)] - [JsonConverter(typeof(StringEnumConverter), true)] - public EquihashSubfamily Subfamily { get; set; } + /// + /// Prefix of a valid testnet-address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h + /// + public ulong AddressPrefixTestnet { get; set; } - public Dictionary Networks { get; set; } - public bool UsesZCashAddressFormat { get; set; } = true; + /// + /// Prefix of a valid integrated address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h + /// + public ulong AddressPrefixIntegrated { get; set; } /// - /// Force use of BitcoinPayoutHandler instead of EquihashPayoutHandler + /// Prefix of a valid integrated testnet-address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h /// - public bool UseBitcoinPayoutHandler { get; set; } -} + public ulong AddressPrefixIntegratedTestnet { get; set; } -public enum ConcealSubfamily -{ - [EnumMember(Value = "none")] - None, + /// + /// Fraction of block reward, the pool really gets to keep + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(1.0d)] + public decimal BlockrewardMultiplier { get; set; } } public enum CryptonoteSubfamily @@ -431,69 +400,6 @@ public enum CryptonightHashType ArgonWRKZ, } -public partial class ConcealCoinTemplate : CoinTemplate -{ - [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - [DefaultValue(ConcealSubfamily.None)] - [JsonConverter(typeof(StringEnumConverter), true)] - public ConcealSubfamily Subfamily { get; set; } - - /// - /// Broader Cryptonight hash family - /// - [JsonConverter(typeof(StringEnumConverter), true)] - [JsonProperty(Order = -5)] - public CryptonightHashType Hash { get; set; } - - /// - /// Set to 0 for automatic selection from blobtemplate - /// - [JsonProperty(Order = -4, DefaultValueHandling = DefaultValueHandling.Include)] - public int HashVariant { get; set; } - - /// - /// Conceal network hashrate = `Difficulty / DifficultyTarget` - /// See: parameter -> DIFFICULTY_TARGET in src/CryptoNoteConfig.h - /// - public ulong DifficultyTarget { get; set; } - - /// - /// Smallest unit for Blockreward formatting - /// - public decimal SmallestUnit { get; set; } - - /// - /// Prefix of a valid address - /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h - /// - public ulong AddressPrefix { get; set; } - - /// - /// Prefix of a valid testnet-address - /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h - /// - public ulong AddressPrefixTestnet { get; set; } - - /// - /// Prefix of a valid integrated address - /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h - /// - public ulong AddressPrefixIntegrated { get; set; } - - /// - /// Prefix of a valid integrated testnet-address - /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h - /// - public ulong AddressPrefixIntegratedTestnet { get; set; } - - /// - /// Fraction of block reward, the pool really gets to keep - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - [DefaultValue(1.0d)] - public decimal BlockrewardMultiplier { get; set; } -} - public partial class CryptonoteCoinTemplate : CoinTemplate { [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] @@ -581,6 +487,115 @@ public partial class CryptonoteCoinTemplate : CoinTemplate public decimal BlockrewardMultiplier { get; set; } } +public enum EquihashSubfamily +{ + [EnumMember(Value = "none")] + None, +} + +public partial class EquihashCoinTemplate : CoinTemplate +{ + public partial class EquihashNetworkParams + { + public string Diff1 { get; set; } + + public int SolutionSize { get; set; } = 1344; + public int SolutionPreambleSize { get; set; } = 3; + public JObject Solver { get; set; } + public string CoinbaseTxNetwork { get; set; } + + public bool PayFoundersReward { get; set; } + public bool PayFundingStream { get; set; } + + // zencash fonder reward + public bool vOuts { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public decimal vPercentFoundersReward { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string vTreasuryRewardAddress { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public decimal vPercentTreasuryReward { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string vSecureNodesRewardAddress { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public decimal percentSecureNodesReward { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string vSuperNodesRewardAddress { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public decimal percentSuperNodesReward { get; set; } + + // zencash founder reward + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public decimal PercentFoundersReward { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string[] FoundersRewardAddresses { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ulong FoundersRewardSubsidySlowStartInterval { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ulong FoundersRewardSubsidyHalvingInterval { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public decimal PercentTreasuryReward { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ulong TreasuryRewardStartBlockHeight { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string[] TreasuryRewardAddresses { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public double TreasuryRewardAddressChangeInterval { get; set; } + + // ZCash "Overwinter" + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public uint? OverwinterActivationHeight { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public uint? OverwinterTxVersion { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public uint? OverwinterTxVersionGroupId { get; set; } + + // ZCash "Sapling" + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public uint? SaplingActivationHeight { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public uint? SaplingTxVersion { get; set; } + + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public uint? SaplingTxVersionGroupId { get; set; } + } + + [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(EquihashSubfamily.None)] + [JsonConverter(typeof(StringEnumConverter), true)] + public EquihashSubfamily Subfamily { get; set; } + + public Dictionary Networks { get; set; } + public bool UsesZCashAddressFormat { get; set; } = true; + + /// + /// Force use of BitcoinPayoutHandler instead of EquihashPayoutHandler + /// + public bool UseBitcoinPayoutHandler { get; set; } +} + +public partial class ErgoCoinTemplate : CoinTemplate +{ +} + public enum EthereumSubfamily { [EnumMember(Value = "none")] @@ -595,16 +610,12 @@ public partial class EthereumCoinTemplate : CoinTemplate public EthereumSubfamily Subfamily { get; set; } /// - /// Which hashing algorithm to use. (ethash, etchash or ubqhash) + /// Which hashing algorithm to use. (ethash, etchash, ubqhash or ethashb3) /// public string Ethasher { get; set; } = "ethash"; } -public partial class ErgoCoinTemplate : CoinTemplate -{ -} - -public partial class ProgpowTemplate : BitcoinTemplate +public partial class ProgpowCoinTemplate : BitcoinTemplate { /// /// Which hashing algorithm to use. (kawpow or firopow) diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index d88b26378..9505385e5 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -27,6 +27,18 @@ public T As() where T : CoinTemplate public string Source { get; set; } } +public partial class AlephiumCoinTemplate +{ + #region Overrides of CoinTemplate + + public override string GetAlgorithmName() + { + return "Blake3"; + } + + #endregion +} + public partial class BeamCoinTemplate { #region Overrides of CoinTemplate @@ -153,8 +165,14 @@ public EquihashNetworkParams GetNetwork(ChainName chain) public override string GetAlgorithmName() { - // TODO: return variant - return "Equihash"; + switch(Symbol) + { + case "VRSC": + return "Verushash"; + default: + // TODO: return variant + return "Equihash"; + } } #endregion @@ -232,11 +250,11 @@ public override string GetAlgorithmName() #endregion } -public partial class ProgpowTemplate +public partial class ProgpowCoinTemplate { #region Overrides of CoinTemplate - public ProgpowTemplate() : base() + public ProgpowCoinTemplate() : base() { progpowLightValue = new Lazy(() => ProgpowFactory.GetProgpow(ComponentContext, Progpower)); diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Allium.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Allium.cs new file mode 100644 index 000000000..b66eca986 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Allium.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("allium")] +public unsafe class Allium : 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.allium(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs new file mode 100644 index 000000000..8c006e5a2 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("blake3")] +public unsafe class Blake3 : 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.blake3(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/CpuPower.cs b/src/Miningcore/Crypto/Hashing/Algorithms/CpuPower.cs new file mode 100644 index 000000000..a69caf12f --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/CpuPower.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("cpupower")] +public unsafe class CpuPower : 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.cpupower(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Power2b.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Power2b.cs new file mode 100644 index 000000000..67af6a238 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Power2b.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("power2b")] +public unsafe class Power2b : 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.power2b(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Skein2.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Skein2.cs new file mode 100644 index 000000000..c5faf0f4c --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Skein2.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("skein2")] +public unsafe class Skein2 : 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.skein2(input, output, (uint)data.Length); + } + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Skydoge.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Skydoge.cs new file mode 100644 index 000000000..6b301e612 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Skydoge.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("skydoge")] +public unsafe class Skydoge : 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.skydoge(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Yescrypt.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Yescrypt.cs new file mode 100644 index 000000000..e6c70f345 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Yescrypt.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yescrypt")] +public unsafe class Yescrypt : 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.yescrypt(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR16.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR16.cs new file mode 100644 index 000000000..a5c8e232a --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR16.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yescryptr16")] +public unsafe class YescryptR16 : 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.yescryptR16(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR32.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR32.cs new file mode 100644 index 000000000..11097137e --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR32.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yescryptr32")] +public unsafe class YescryptR32 : 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.yescryptR32(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR8.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR8.cs new file mode 100644 index 000000000..132811355 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/YescryptR8.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yescryptr8")] +public unsafe class YescryptR8 : 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.yescryptR8(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Yespower.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Yespower.cs new file mode 100644 index 000000000..c3e991b42 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Yespower.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yespower")] +public unsafe class Yespower : 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.yespower(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerIC.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerIC.cs new file mode 100644 index 000000000..6365c5700 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerIC.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yespoweric")] +public unsafe class YespowerIC : 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.yespowerIC(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerR16.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerR16.cs new file mode 100644 index 000000000..92929d0f7 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerR16.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yespowerr16")] +public unsafe class YespowerR16 : 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.yespowerR16(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/YespowerTIDE.cs b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerTIDE.cs new file mode 100644 index 000000000..d26b09b8b --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/YespowerTIDE.cs @@ -0,0 +1,21 @@ +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("yespowertide")] +public unsafe class YespowerTIDE : 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.yespowerTIDE(input, output, (uint) data.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs new file mode 100644 index 000000000..7b3567b6f --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs @@ -0,0 +1,169 @@ +using System.Diagnostics; +using System.Text; +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ethash.Ethashb3; + +[Identifier("ethashb3")] +public class Cache : IEthashCache +{ + public Cache(ulong epoch, string dagDir = null) + { + Epoch = epoch; + this.dagDir = dagDir; + LastUsed = DateTime.Now; + } + + private IntPtr handle = IntPtr.Zero; + private bool isGenerated = false; + private readonly object genLock = new(); + internal static IMessageBus messageBus; + public ulong Epoch { get; } + private string dagDir; + public DateTime LastUsed { get; set; } + + public static unsafe string GetDefaultdagDirectory() + { + var chars = new byte[512]; + + fixed (byte* data = chars) + { + if(EthHashB3.ethash_get_default_dirname(data, chars.Length)) + { + int length; + for(length = 0; length < chars.Length; length++) + { + if(data[length] == 0) + break; + } + + return Encoding.UTF8.GetString(data, length); + } + } + + return null; + } + + public void Dispose() + { + if(handle != IntPtr.Zero) + { + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + EthHashB3.ethash_full_delete(handle); + } + // Light Cache + else + { + EthHashB3.ethash_light_delete(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; + var block = Epoch * RethereumConstants.EpochLength; + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + logger.Debug(() => $"Generating DAG for epoch {Epoch}"); + logger.Debug(() => $"Epoch length used: {RethereumConstants.EpochLength}"); + + // Generate a temporary cache + var light = EthHashB3.ethash_light_new(block); + + // Generate the actual DAG + handle = EthHashB3.ethash_full_new(dagDir, light, progress => + { + logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); + + return !ct.IsCancellationRequested ? 0 : 1; + }); + + if(handle == IntPtr.Zero) + throw new OutOfMemoryException("ethash_full_new IO or memory error"); + + if(light != IntPtr.Zero) + EthHashB3.ethash_light_delete(light); + + logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); + } + // Light Cache + else + { + logger.Debug(() => $"Generating cache for epoch {Epoch}"); + + handle = EthHashB3.ethash_light_new(block); + + logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}"); + } + + isGenerated = true; + } + } + }, ct); + } + } + + public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) + { + Contract.RequiresNonNull(hash); + + var sw = Stopwatch.StartNew(); + + mixDigest = null; + result = null; + + var value = new EthHashB3.ethash_return_value(); + + // Full DAG + if(!string.IsNullOrEmpty(dagDir)) + { + fixed (byte* input = hash) + { + EthHashB3.ethash_full_compute(handle, input, nonce, ref value); + } + } + // Light Cache + else + { + fixed(byte* input = hash) + { + EthHashB3.ethash_light_compute(handle, input, nonce, ref value); + } + } + + if(value.success) + { + mixDigest = value.mix_hash.value; + result = value.result.value; + } + + messageBus?.SendTelemetry("Ethashb3", TelemetryCategory.Hash, sw.Elapsed, value.success); + + return value.success; + } +} \ No newline at end of file diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs new file mode 100644 index 000000000..650628ef0 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs @@ -0,0 +1,92 @@ +using System.Text; +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using Miningcore.Native; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ethash.Ethashb3; + +[Identifier("ethashb3")] +public class Ethashb3Light : IEthashLight +{ + public void Setup(int totalCache, ulong hardForkBlock, string dagDir = null) + { + this.numCaches = totalCache; + this.dagDir = dagDir; + } + + 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; + private string dagDir; + public string AlgoName { get; } = "EthashB3"; + + public void Dispose() + { + foreach(var value in caches.Values) + value.Dispose(); + } + + public async Task GetCacheAsync(ILogger logger, ulong block, CancellationToken ct) + { + var epoch = block / RethereumConstants.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, dagDir); + } + + 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, dagDir); + +#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/Native/EthHashB3.cs b/src/Miningcore/Native/EthHashB3.cs new file mode 100644 index 000000000..0b9378263 --- /dev/null +++ b/src/Miningcore/Native/EthHashB3.cs @@ -0,0 +1,112 @@ +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Native; + +public static unsafe class EthHashB3 +{ + [StructLayout(LayoutKind.Sequential)] + public struct ethash_h256_t + { + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U8, SizeConst = 32)] public byte[] value; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ethash_return_value + { + public ethash_h256_t result; + public ethash_h256_t mix_hash; + + [MarshalAs(UnmanagedType.U1)] public bool success; + } + + public delegate int ethash_callback_t(uint progress); + + /// + /// Allocate and initialize a new ethash_light handler + /// + /// The block number for which to create the handler + /// Newly allocated ethash_light handler or NULL + [DllImport("libethhashb3", EntryPoint = "ethash_light_new_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_light_new(ulong block_number); + + /// + /// Frees a previously allocated ethash_light handler + /// + /// The light handler to free + [DllImport("libethhashb3", EntryPoint = "ethash_light_delete_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_light_delete(IntPtr handle); + + /// + /// Calculate the light client data + /// + /// The light client handler + /// The 32-Byte header hash to pack into the mix + /// The nonce to pack into the mix + /// an object of ethash_return_value_t holding the return values + [DllImport("libethhashb3", EntryPoint = "ethash_light_compute_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_light_compute(IntPtr handle, byte* header_hash, ulong nonce, ref ethash_return_value result); + + /// + /// Allocate and initialize a new ethash_full handler + /// + /// Directory where generated DAGs reside + /// The light handler containing the cache. + /// + /// A callback function with signature of @ref ethash_callback_t + /// It accepts an unsigned with which a progress of DAG calculation + /// can be displayed. If all goes well the callback should return 0. + /// If a non-zero value is returned then DAG generation will stop. + /// Be advised. A progress value of 100 means that DAG creation is + /// almost complete and that this function will soon return succesfully. + /// It does not mean that the function has already had a succesfull return. + /// + /// + [DllImport("libethhashb3", EntryPoint = "ethash_full_new_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_full_new(string dagDir, IntPtr light, ethash_callback_t callback); + + /// + /// Frees a previously allocated ethash_full handler + /// + /// The full handler to free + [DllImport("libethhashb3", EntryPoint = "ethash_full_delete_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_full_delete(IntPtr handle); + + /// + /// Calculate the full client data + /// + /// The full client handler + /// The 32-Byte header hash to pack into the mix + /// The nonce to pack into the mix + /// an object of ethash_return_value_t holding the return values + [DllImport("libethhashb3", EntryPoint = "ethash_full_compute_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_full_compute(IntPtr handle, byte* header_hash, ulong nonce, ref ethash_return_value result); + + /// + /// Get a pointer to the full DAG data + /// + /// The full handler to free + [DllImport("libethhashb3", EntryPoint = "ethash_full_dag_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_full_dag(IntPtr handle); + + /// + /// Get the size of the DAG data + /// + /// The full handler to free + [DllImport("libethhashb3", EntryPoint = "ethash_full_dag_size_export", CallingConvention = CallingConvention.Cdecl)] + public static extern ulong ethash_full_dag_size(IntPtr handle); + + /// + /// Calculate the seedhash for a given block number + /// + /// The full handler to free + [DllImport("libethhashb3", EntryPoint = "ethash_get_seedhash_export", CallingConvention = CallingConvention.Cdecl)] + public static extern ethash_h256_t ethash_get_seedhash(ulong block_number); + + /// + /// Get the default DAG directory + /// + [DllImport("libethhashb3", EntryPoint = "ethash_get_default_dirname_export", CallingConvention = CallingConvention.Cdecl)] + public static extern bool ethash_get_default_dirname(byte* data, int length); +} \ No newline at end of file diff --git a/src/Miningcore/Native/Multihash.cs b/src/Miningcore/Native/Multihash.cs index 96ff81619..f3799c463 100644 --- a/src/Miningcore/Native/Multihash.cs +++ b/src/Miningcore/Native/Multihash.cs @@ -67,6 +67,9 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "skein_export", CallingConvention = CallingConvention.Cdecl)] public static extern void skein(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "skein2_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void skein2(byte* input, void* output, uint inputLength); + [DllImport("libmultihash", EntryPoint = "groestl_export", CallingConvention = CallingConvention.Cdecl)] public static extern void groestl(byte* input, void* output, uint inputLength); @@ -81,6 +84,9 @@ 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); + + [DllImport("libmultihash", EntryPoint = "blake3_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void blake3(byte* input, void* output, uint inputLength); [DllImport("libmultihash", EntryPoint = "dcrypt_export", CallingConvention = CallingConvention.Cdecl)] public static extern void dcrypt(byte* input, void* output, uint inputLength); @@ -153,4 +159,40 @@ public static unsafe class Multihash [DllImport("libmultihash", EntryPoint = "minotaurx_export", CallingConvention = CallingConvention.Cdecl)] public static extern void minotaurx(byte* input, void* output); + + [DllImport("libmultihash", EntryPoint = "skydoge_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void skydoge(byte* input, void* output, uint inputLength); + + [DllImport("libmultihash", EntryPoint = "yescrypt_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void yescrypt(byte* input, void* output, uint inputLength); + + [DllImport("libmultihash", EntryPoint = "yescryptR8_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void yescryptR8(byte* input, void* output, uint inputLength); + + [DllImport("libmultihash", EntryPoint = "yescryptR16_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void yescryptR16(byte* input, void* output, uint inputLength); + + [DllImport("libmultihash", EntryPoint = "yescryptR32_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void yescryptR32(byte* input, void* output, uint inputLength); + + [DllImport("libmultihash", EntryPoint = "allium_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void allium(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); + + [DllImport("libmultihash", EntryPoint = "power2b_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void power2b(byte* input, void* output, uint inputLength); + + [DllImport("libmultihash", EntryPoint = "yespower_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void yespower(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 = "yespowerTIDE_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void yespowerTIDE(byte* input, void* output, uint inputLength); } diff --git a/src/Miningcore/Nicehash/NicehashService.cs b/src/Miningcore/Nicehash/NicehashService.cs index 120732c5f..7b3b659fb 100644 --- a/src/Miningcore/Nicehash/NicehashService.cs +++ b/src/Miningcore/Nicehash/NicehashService.cs @@ -54,6 +54,9 @@ public NicehashService( private string GetNicehashAlgo(string coin, string algo) { + if(coin == "Beam" && algo == "BeamHash") + return "beamv3"; + if(coin == "Monero" && algo == "RandomX") return "randomxmonero"; diff --git a/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs index a1b424ae5..b61a5b3db 100644 --- a/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs @@ -84,9 +84,11 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, IMin // delete discarded shares if(shareCutOffDate.HasValue) { + // warning: some multichains coins like ALPH have none-linear blockHeight, so we CAN NOT discard old shares if older blocks are still pending + var pendingBlockBefore = await blockRepo.GetBlockBeforeCountAsync(con, poolConfig.Id, new[] { BlockStatus.Pending }, block.Created); var cutOffCount = await shareRepo.CountSharesBeforeAsync(con, tx, poolConfig.Id, shareCutOffDate.Value, ct); - if(cutOffCount > 0) + if(cutOffCount > 0 && pendingBlockBefore < 1) { await LogDiscardedSharesAsync(ct, poolConfig, block, shareCutOffDate.Value); diff --git a/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs index 69c0b73b0..9a5ee9c73 100644 --- a/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs @@ -78,9 +78,11 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, IMin // delete discarded shares if(shareCutOffDate.HasValue) { + // warning: some multichains coins like ALPH have none-linear blockHeight, so we CAN NOT discard old shares if older blocks are still pending + var pendingBlockBefore = await blockRepo.GetBlockBeforeCountAsync(con, poolConfig.Id, new[] { BlockStatus.Pending }, block.Created); var cutOffCount = await shareRepo.CountSharesBeforeAsync(con, tx, poolConfig.Id, shareCutOffDate.Value, ct); - if(cutOffCount > 0) + if(cutOffCount > 0 && pendingBlockBefore < 1) { await LogDiscardedSharesAsync(ct, poolConfig, block, shareCutOffDate.Value); diff --git a/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs index 9d87bd1ff..aac23dd7b 100644 --- a/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs @@ -15,16 +15,20 @@ public class SOLOPaymentScheme : IPayoutScheme { public SOLOPaymentScheme( IShareRepository shareRepo, + IBlockRepository blockRepo, IBalanceRepository balanceRepo) { Contract.RequiresNonNull(shareRepo); + Contract.RequiresNonNull(blockRepo); Contract.RequiresNonNull(balanceRepo); this.shareRepo = shareRepo; + this.blockRepo = blockRepo; this.balanceRepo = balanceRepo; } private readonly IBalanceRepository balanceRepo; + private readonly IBlockRepository blockRepo; private readonly IShareRepository shareRepo; private static readonly ILogger logger = LogManager.GetLogger("SOLO Payment", typeof(SOLOPaymentScheme)); @@ -55,9 +59,11 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, IMin // delete discarded shares if(shareCutOffDate.HasValue) { + // warning: some multichains coins like ALPH have none-linear blockHeight, so we CAN NOT discard old shares if older blocks are still pending + var pendingBlockBefore = await blockRepo.GetBlockBeforeCountAsync(con, poolConfig.Id, new[] { BlockStatus.Pending }, block.Created); var cutOffCount = await shareRepo.CountSharesByMinerAsync(con, tx, poolConfig.Id, block.Miner, ct); - if(cutOffCount > 0) + if(cutOffCount > 0 && pendingBlockBefore < 1) { logger.Info(() => $"Deleting {cutOffCount} discarded shares for {block.Miner}"); diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs index da17b0538..e5c53efb2 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs @@ -93,12 +93,24 @@ public async Task GetBlockBeforeAsync(IDbConnection con, string poolId, B return (await con.QueryAsync(query, new { poolId, - before, - status = status.Select(x => x.ToString().ToLower()).ToArray() + status = status.Select(x => x.ToString().ToLower()).ToArray(), + before })) .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, + status = status.Select(x => x.ToString().ToLower()).ToArray(), + before + })); + } public Task GetPoolBlockCountAsync(IDbConnection con, string poolId, CancellationToken ct) { diff --git a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs index abb31884c..26b355d9f 100644 --- a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs @@ -13,6 +13,7 @@ public interface IBlockRepository Task PageBlocksAsync(IDbConnection con, 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 GetBlockBeforeCountAsync(IDbConnection con, string poolId, BlockStatus[] status, DateTime before); Task GetPoolBlockCountAsync(IDbConnection con, string poolId, CancellationToken ct); Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId); Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, string poolId, long height, string type); diff --git a/src/Miningcore/build-libs-linux.sh b/src/Miningcore/build-libs-linux.sh index 97f4569ba..a65082c85 100755 --- a/src/Miningcore/build-libs-linux.sh +++ b/src/Miningcore/build-libs-linux.sh @@ -26,6 +26,7 @@ export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_AVX $HAVE (cd ../Native/libbeamhash && make clean && make) && mv ../Native/libbeamhash/libbeamhash.so "$OutDir" (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/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" diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 2520acf5b..9491026fe 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -1535,6 +1535,7 @@ } ] }, + "hasMWEB": true, "shareMultiplier": 65536, "explorerBlockLink": "https://chainz.cryptoid.info/ltc/block.dws?$height$.htm", "explorerTxLink": "https://chainz.cryptoid.info/ltc/tx.dws?{0}.htm", @@ -2325,6 +2326,7 @@ "hash": "reverse", "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}" @@ -3856,7 +3858,7 @@ } }, "usesZCashAddressFormat": false, - "useBitcoinPayoutHandler": true, + "useBitcoinPayoutHandler": false, "explorerBlockLink": "https://explorer.veruscoin.io/block/$height$", "explorerTxLink": "https://explorer.veruscoin.io/tx/{0}", "explorerAccountLink": "https://explorer.veruscoin.io/address/{0}" @@ -4492,6 +4494,24 @@ "explorerAccountLink": "https://pinkscan.org/address/{0}", "ethasher": "ethash" }, + "rethereum": { + "name": "Rethereum", + "canonicalName": "Rethereum", + "symbol": "RTH", + "family": "ethereum", + "website": "https://www.rethereum.org/", + "market": "", + "twitter": "", + "telegram": "", + "discord": "https://discord.gg/xCB4AJDEFb", + "explorerBlockLinks": { + "block": "https://explorer.rethereum.org/block/$height$", + "uncle": "https://explorer.rethereum.org/block/$hash$" + }, + "explorerTxLink": "https://explorer.rethereum.org/tx/{0}", + "explorerAccountLink": "https://explorer.rethereum.org/address/{0}", + "ethasher": "ethashb3" + }, "ubiq": { "name": "Ubiq", "canonicalName": "Ubiq", @@ -4515,13 +4535,27 @@ "canonicalName": "Ergo", "symbol": "ERG", "family": "ergo", - "website": "", + "website": "https://ergoplatform.org/", "market": "", - "twitter": "", - "telegram": "", - "discord": "", + "twitter": "https://twitter.com/Ergo_Platform", + "telegram": "https://t.me/ergoplatform", + "discord": "https://discord.gg/RC8M4Bkgsy", "explorerBlockLink": "https://explorer.ergoplatform.com/en/blocks/$hash$", "explorerTxLink": "https://explorer.ergoplatform.com/en/transactions/{0}", "explorerAccountLink": "https://explorer.ergoplatform.com/en/addresses/{0}" + }, + "alephium": { + "name": "Alephium", + "canonicalName": "Alephium", + "symbol": "ALPH", + "family": "alephium", + "website": "https://alephium.org/", + "market": "https://coinmarketcap.com/currencies/alephium/", + "twitter": "https://twitter.com/alephium", + "telegram": "https://t.me/alephiumgroup", + "discord": "https://discord.gg/JErgRBfRSB", + "explorerBlockLink": "https://explorer.alephium.org/blocks/$hash$", + "explorerTxLink": "https://explorer.alephium.org/transactions/{0}", + "explorerAccountLink": "https://explorer.alephium.org/addresses/{0}" } } diff --git a/src/Native/libbeamhash/Makefile b/src/Native/libbeamhash/Makefile index 96b1800a0..44685206a 100644 --- a/src/Native/libbeamhash/Makefile +++ b/src/Native/libbeamhash/Makefile @@ -1,5 +1,5 @@ CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable $(CPU_FLAGS) $(HAVE_FEATURE) -CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS) $(HAVE_FEATURE) +CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -funroll-loops -fomit-frame-pointer -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS) $(HAVE_FEATURE) LDFLAGS += -shared TARGET = libbeamhash.so diff --git a/src/Native/libethhashb3/Makefile b/src/Native/libethhashb3/Makefile new file mode 100644 index 000000000..237cb8dd5 --- /dev/null +++ b/src/Native/libethhashb3/Makefile @@ -0,0 +1,16 @@ +CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable $(CPU_FLAGS) $(HAVE_FEATURE) +CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS) $(HAVE_FEATURE) +LDFLAGS += -shared +TARGET = libethhashb3.so + +OBJECTS = internal.o io.o io_posix.o sha3.o exports.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libethhashb3/compiler.h b/src/Native/libethhashb3/compiler.h new file mode 100644 index 000000000..d43eb5df6 --- /dev/null +++ b/src/Native/libethhashb3/compiler.h @@ -0,0 +1,32 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file compiler.h + * @date 2014 + */ +#pragma once + +// Visual Studio doesn't support the inline keyword in C mode +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline __inline +#endif + +// pretend restrict is a standard keyword +#if defined(_MSC_VER) +#define restrict __restrict +#else +#define restrict __restrict__ +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/data_sizes.h b/src/Native/libethhashb3/data_sizes.h new file mode 100644 index 000000000..b88f80e4f --- /dev/null +++ b/src/Native/libethhashb3/data_sizes.h @@ -0,0 +1,812 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software FoundationUUU,either version 3 of the LicenseUUU,or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be usefulU, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If notUUU,see . +*/ + +/** @file data_sizes.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once + +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// 2048 Epochs (~20 years) worth of tabulated DAG sizes + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// CacheSizeBytesInit = 2^24, +// CacheGrowth = 2^17, +// HashBytes = 64, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = +// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + + +static const uint64_t dag_sizes[2048] = { + 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, + 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, + 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, + 1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U, + 1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U, + 1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U, + 1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U, + 1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U, + 1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U, + 1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U, + 1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U, + 1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U, + 1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U, + 1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U, + 1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U, + 1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U, + 1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U, + 1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U, + 1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U, + 1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U, + 1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U, + 1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U, + 1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U, + 2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U, + 2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U, + 2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U, + 2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U, + 2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U, + 2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U, + 2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U, + 2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U, + 2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U, + 2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U, + 2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U, + 2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U, + 2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U, + 2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U, + 2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U, + 2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U, + 2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U, + 2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U, + 2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U, + 2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U, + 2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U, + 2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U, + 2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U, + 3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U, + 3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U, + 3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U, + 3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U, + 3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U, + 3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U, + 3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U, + 3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U, + 3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U, + 3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U, + 3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U, + 3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U, + 3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U, + 3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U, + 3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U, + 3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U, + 3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U, + 3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U, + 3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U, + 3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U, + 3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U, + 3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U, + 3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U, + 3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U, + 4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U, + 4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U, + 4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U, + 4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U, + 4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U, + 4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U, + 4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U, + 4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U, + 4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U, + 4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U, + 4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U, + 4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U, + 4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U, + 4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U, + 4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U, + 4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U, + 4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U, + 4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U, + 4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U, + 4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U, + 4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U, + 4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U, + 4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U, + 4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U, + 5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U, + 5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U, + 5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U, + 5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U, + 5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U, + 5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U, + 5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U, + 5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U, + 5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U, + 5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U, + 5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U, + 5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U, + 5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U, + 5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U, + 5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U, + 5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U, + 5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U, + 5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U, + 5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U, + 5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U, + 5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U, + 5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U, + 5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U, + 5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U, + 6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U, + 6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U, + 6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U, + 6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U, + 6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U, + 6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U, + 6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U, + 6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U, + 6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U, + 6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U, + 6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U, + 6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U, + 6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U, + 6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U, + 6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U, + 6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U, + 6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U, + 6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U, + 6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U, + 6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U, + 6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U, + 6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U, + 6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U, + 6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U, + 7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U, + 7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U, + 7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U, + 7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U, + 7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U, + 7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U, + 7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U, + 7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U, + 7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U, + 7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U, + 7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U, + 7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U, + 7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U, + 7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U, + 7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U, + 7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U, + 7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U, + 7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U, + 7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U, + 7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U, + 7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U, + 7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U, + 7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U, + 7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U, + 8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U, + 8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U, + 8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U, + 8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U, + 8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U, + 8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U, + 8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U, + 8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U, + 8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U, + 8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U, + 8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U, + 8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U, + 8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U, + 8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U, + 8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U, + 8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U, + 8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U, + 8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U, + 8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U, + 8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U, + 8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U, + 8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U, + 8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U, + 9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U, + 9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U, + 9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U, + 9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U, + 9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U, + 9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U, + 9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U, + 9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U, + 9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U, + 9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U, + 9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U, + 9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U, + 9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U, + 9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U, + 9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U, + 9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U, + 9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U, + 9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U, + 9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U, + 9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U, + 9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U, + 9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U, + 9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U, + 9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U, + 10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U, + 10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U, + 10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U, + 10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U, + 10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U, + 10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U, + 10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U, + 10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U, + 10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U, + 10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U, + 10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U, + 10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U, + 10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U, + 10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U, + 10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U, + 10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U, + 10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U, + 10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U, + 10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U, + 10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U, + 10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U, + 10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U, + 10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U, + 10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U, + 11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U, + 11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U, + 11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U, + 11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U, + 11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U, + 11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U, + 11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U, + 11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U, + 11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U, + 11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U, + 11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U, + 11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U, + 11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U, + 11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U, + 11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U, + 11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U, + 11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U, + 11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U, + 11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U, + 11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U, + 11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U, + 11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U, + 11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U, + 11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U, + 12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U, + 12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U, + 12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U, + 12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U, + 12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U, + 12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U, + 12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U, + 12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U, + 12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U, + 12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U, + 12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U, + 12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U, + 12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U, + 12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U, + 12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U, + 12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U, + 12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U, + 12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U, + 12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U, + 12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U, + 12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U, + 12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U, + 12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U, + 12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U, + 13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U, + 13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U, + 13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U, + 13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U, + 13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U, + 13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U, + 13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U, + 13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U, + 13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U, + 13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U, + 13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U, + 13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U, + 13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U, + 13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U, + 13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U, + 13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U, + 13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U, + 13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U, + 13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U, + 13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U, + 13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U, + 13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U, + 13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U, + 13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U, + 14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U, + 14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U, + 14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U, + 14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U, + 14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U, + 14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U, + 14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U, + 14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U, + 14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U, + 14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U, + 14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U, + 14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U, + 14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U, + 14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U, + 14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U, + 14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U, + 14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U, + 14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U, + 14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U, + 14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U, + 14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U, + 14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U, + 14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U, + 14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U, + 15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U, + 15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U, + 15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U, + 15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U, + 15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U, + 15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U, + 15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U, + 15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U, + 15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U, + 15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U, + 15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U, + 15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U, + 15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U, + 15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U, + 15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U, + 15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U, + 15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U, + 15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U, + 15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U, + 15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U, + 15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U, + 15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U, + 15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U, + 16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U, + 16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U, + 16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U, + 16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U, + 16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U, + 16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U, + 16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U, + 16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U, + 16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U, + 16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U, + 16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U, + 16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U, + 16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U, + 16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U, + 16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U, + 16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U, + 16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U, + 16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U, + 16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U, + 16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U, + 16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U, + 16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U, + 16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U, + 16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U, + 17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U, + 17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U, + 17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U, + 17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U, + 17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U, + 17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U, + 17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U, + 17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U, + 17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U, + 17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U, + 17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U, + 17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U, + 17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U, + 17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U, + 17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U, + 17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U, + 17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U, + 17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U, + 17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U, + 17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U, + 17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U, + 17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U, + 17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U, + 17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U, + 18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U, + 18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U, + 18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U, + 18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U, + 18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U, + 18228444544U, 18236833408U, 18245220736U +}; + + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// DataSetSizeBytesInit = 2^30, +// MixBytes = 128, +// DataSetGrowth = 2^23, +// HashBytes = 64, +// CacheMultiplier = 1024, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + +const uint64_t cache_sizes[2048] = { + 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, + 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, + 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, + 19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U, + 20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U, + 21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U, + 22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U, + 23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U, + 24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U, + 25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U, + 25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U, + 26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U, + 27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U, + 28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U, + 29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U, + 30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U, + 31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U, + 32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U, + 33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U, + 34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U, + 35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U, + 36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U, + 36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U, + 37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U, + 38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U, + 39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U, + 40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U, + 41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U, + 42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U, + 43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U, + 44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U, + 45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U, + 46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U, + 47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U, + 47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U, + 48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U, + 49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U, + 50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U, + 51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U, + 52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U, + 53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U, + 54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U, + 55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U, + 56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U, + 57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U, + 58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U, + 58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U, + 59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U, + 60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U, + 61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U, + 62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U, + 63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U, + 64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U, + 65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U, + 66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U, + 67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U, + 68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U, + 69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U, + 69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U, + 70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U, + 71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U, + 72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U, + 73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U, + 74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U, + 75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U, + 76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U, + 77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U, + 78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U, + 79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U, + 80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U, + 81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U, + 81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U, + 82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U, + 83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U, + 84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U, + 85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U, + 86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U, + 87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U, + 88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U, + 89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U, + 90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U, + 91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U, + 92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U, + 92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U, + 93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U, + 94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U, + 95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U, + 96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U, + 97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U, + 98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U, + 99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U, + 100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U, + 100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U, + 101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U, + 102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U, + 103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U, + 104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U, + 104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U, + 105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U, + 106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U, + 107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U, + 108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U, + 108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U, + 109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U, + 110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U, + 111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U, + 111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U, + 112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U, + 113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U, + 114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U, + 115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U, + 115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U, + 116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U, + 117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U, + 118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U, + 119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U, + 119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U, + 120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U, + 121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U, + 122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U, + 122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U, + 123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U, + 124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U, + 125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U, + 126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U, + 126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U, + 127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U, + 128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U, + 129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U, + 130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U, + 130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U, + 131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U, + 132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U, + 133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U, + 133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U, + 134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U, + 135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U, + 136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U, + 137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U, + 137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U, + 138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U, + 139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U, + 140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U, + 141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U, + 141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U, + 142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U, + 143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U, + 144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U, + 144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U, + 145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U, + 146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U, + 147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U, + 148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U, + 148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U, + 149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U, + 150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U, + 151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U, + 152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U, + 152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U, + 153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U, + 154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U, + 155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U, + 155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U, + 156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U, + 157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U, + 158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U, + 159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U, + 159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U, + 160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U, + 161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U, + 162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U, + 163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U, + 163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U, + 164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U, + 165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U, + 166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U, + 166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U, + 167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U, + 168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U, + 169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U, + 170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U, + 170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U, + 171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U, + 172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U, + 173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U, + 174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U, + 174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U, + 175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U, + 176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U, + 177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U, + 177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U, + 178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U, + 179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U, + 180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U, + 181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U, + 181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U, + 182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U, + 183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U, + 184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U, + 185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U, + 185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U, + 186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U, + 187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U, + 188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U, + 189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U, + 189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U, + 190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U, + 191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U, + 192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U, + 192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U, + 193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U, + 194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U, + 195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U, + 196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U, + 196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U, + 197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U, + 198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U, + 199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U, + 200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U, + 200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U, + 201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U, + 202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U, + 203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U, + 203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U, + 204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U, + 205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U, + 206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U, + 207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U, + 207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U, + 208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U, + 209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U, + 210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U, + 211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U, + 211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U, + 212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U, + 213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U, + 214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U, + 214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U, + 215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U, + 216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U, + 217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U, + 218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U, + 218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U, + 219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U, + 220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U, + 221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U, + 222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U, + 222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U, + 223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U, + 224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U, + 225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U, + 225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U, + 226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U, + 227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U, + 228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U, + 229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U, + 229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U, + 230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U, + 231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U, + 232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U, + 233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U, + 233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U, + 234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U, + 235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U, + 236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U, + 236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U, + 237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U, + 238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U, + 239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U, + 240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U, + 240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U, + 241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U, + 242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U, + 243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U, + 244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U, + 244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U, + 245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U, + 246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U, + 247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U, + 247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U, + 248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U, + 249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U, + 250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U, + 251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U, + 251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U, + 252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U, + 253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U, + 254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U, + 255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U, + 255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U, + 256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U, + 257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U, + 258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U, + 258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U, + 259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U, + 260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U, + 261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U, + 262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U, + 262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U, + 263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U, + 264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U, + 265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U, + 266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U, + 266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U, + 267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U, + 268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U, + 269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U, + 270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U, + 270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U, + 271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U, + 272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U, + 273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U, + 273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U, + 274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U, + 275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U, + 276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U, + 277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U, + 277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U, + 278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U, + 279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U, + 280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U, + 281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U, + 281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U, + 282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U, + 283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U, + 284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U, + 284950208U, 285081536U +}; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/dllmain.cpp b/src/Native/libethhashb3/dllmain.cpp new file mode 100644 index 000000000..c54995ec9 --- /dev/null +++ b/src/Native/libethhashb3/dllmain.cpp @@ -0,0 +1,18 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} \ No newline at end of file diff --git a/src/Native/libethhashb3/endian.h b/src/Native/libethhashb3/endian.h new file mode 100644 index 000000000..b1f33ab8e --- /dev/null +++ b/src/Native/libethhashb3/endian.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include "compiler.h" + +#if defined(__MINGW32__) || defined(_WIN32) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) + # include +#elif defined(__OpenBSD__) || defined(__SVR4) + # include +#elif defined(__APPLE__) +# include +#elif defined( BSD ) && (BSD >= 199103) + # include +#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ ) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ ) + # define BIG_ENDIAN 1234 + # define BYTE_ORDER BIG_ENDIAN +#else +# include +#endif + +#if defined(_WIN32) +#include +#define ethash_swap_u32(input_) _byteswap_ulong(input_) +#define ethash_swap_u64(input_) _byteswap_uint64(input_) +#elif defined(__APPLE__) +#include +#define ethash_swap_u32(input_) OSSwapInt32(input_) +#define ethash_swap_u64(input_) OSSwapInt64(input_) +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) +#define ethash_swap_u32(input_) bswap32(input_) +#define ethash_swap_u64(input_) bswap64(input_) +#elif defined(__OpenBSD__) +#include +#define ethash_swap_u32(input_) swap32(input_) +#define ethash_swap_u64(input_) swap64(input_) +#else // posix +#include +#define ethash_swap_u32(input_) bswap_32(input_) +#define ethash_swap_u64(input_) bswap_64(input_) +#endif + + +#if LITTLE_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_ ,src_) dst_ = src_ +#define fix_endian32_same(val_) +#define fix_endian64(dst_, src_) dst_ = src_ +#define fix_endian64_same(val_) +#define fix_endian_arr32(arr_, size_) +#define fix_endian_arr64(arr_, size_) + +#elif BIG_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_) +#define fix_endian32_same(val_) val_ = ethash_swap_u32(val_) +#define fix_endian64(dst_, src_) dst_ = ethash_swap_u64(src_) +#define fix_endian64_same(val_) val_ = ethash_swap_u64(val_) +#define fix_endian_arr32(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_); ++i_) { \ + arr_[i_] = ethash_swap_u32(arr_[i_]); \ + } \ + } while (0) +#define fix_endian_arr64(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_); ++i_) { \ + arr_[i_] = ethash_swap_u64(arr_[i_]); \ + } \ + } while (0) +#else +# error "endian not supported" +#endif // BYTE_ORDER \ No newline at end of file diff --git a/src/Native/libethhashb3/ethash.h b/src/Native/libethhashb3/ethash.h new file mode 100644 index 000000000..484325449 --- /dev/null +++ b/src/Native/libethhashb3/ethash.h @@ -0,0 +1,147 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ + +/** @file ethash.h +* @date 2015 +*/ +#pragma once + +#include +#include +#include +#include +#include "compiler.h" + +#define ETHASH_REVISION 23 +#define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30 +#define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23 +#define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24 +#define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17 +#define ETHASH_EPOCH_LENGTH 32000U +#define ETHASH_MIX_BYTES 128 +#define ETHASH_HASH_BYTES 64 +#define ETHASH_DATASET_PARENTS 256 +#define ETHASH_CACHE_ROUNDS 3 +#define ETHASH_ACCESSES 64 +#define ETHASH_DAG_MAGIC_NUM_SIZE 8 +#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE + +#ifdef __cplusplus +extern "C" { +#endif + +/// Type of a seedhash/blockhash e.t.c. +typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t; + +// convenience macro to statically initialize an h256_t +// usage: +// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... ) +// have to provide all 32 values. If you don't provide all the rest +// will simply be unitialized (not guranteed to be 0) +#define ethash_h256_static_init(...) \ + { {__VA_ARGS__} } + +struct ethash_light; +typedef struct ethash_light* ethash_light_t; +struct ethash_full; +typedef struct ethash_full* ethash_full_t; +typedef int(*ethash_callback_t)(unsigned); + +typedef struct ethash_return_value { + ethash_h256_t result; + ethash_h256_t mix_hash; + bool success; +} ethash_return_value_t; + +/** + * Allocate and initialize a new ethash_light handler + * + * @param block_number The block number for which to create the handler + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new(uint64_t block_number); +/** + * Frees a previously allocated ethash_light handler + * @param light The light handler to free + */ +void ethash_light_delete(ethash_light_t light); +/** + * Calculate the light client data + * + * @param light The light client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return an object of ethash_return_value_t holding the return values + */ +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +); + +/** + * Allocate and initialize a new ethash_full handler + * + * @param light The light handler containing the cache. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * Be advised. A progress value of 100 means that DAG creation is + * almost complete and that this function will soon return succesfully. + * It does not mean that the function has already had a succesfull return. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback); + +/** + * Frees a previously allocated ethash_full handler + * @param full The light handler to free + */ +void ethash_full_delete(ethash_full_t full); +/** + * Calculate the full client data + * + * @param full The full client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return An object of ethash_return_value to hold the return value + */ +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +); +/** + * Get a pointer to the full DAG data + */ +void const* ethash_full_dag(ethash_full_t full); +/** + * Get the size of the DAG data + */ +uint64_t ethash_full_dag_size(ethash_full_t full); + +/** + * Calculate the seedhash for a given block number + */ +ethash_h256_t ethash_get_seedhash(uint64_t block_number); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/exports.cpp b/src/Native/libethhashb3/exports.cpp new file mode 100644 index 000000000..3bd8e2df4 --- /dev/null +++ b/src/Native/libethhashb3/exports.cpp @@ -0,0 +1,98 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "sha3.h" +#include "internal.h" +#include "ethash.h" + +extern "C" bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif + +extern "C" MODULE_API uint64_t ethash_get_datasize_export(uint64_t const block_number) +{ + return ethash_get_datasize(block_number); +} + +extern "C" MODULE_API uint64_t ethash_get_cachesize_export(uint64_t const block_number) +{ + return ethash_get_cachesize(block_number); +} + +extern "C" MODULE_API ethash_light_t ethash_light_new_export(uint64_t block_number) +{ + return ethash_light_new(block_number); +} + +extern "C" MODULE_API void ethash_light_delete_export(ethash_light_t light) +{ + ethash_light_delete(light); +} + +extern "C" MODULE_API void ethash_light_compute_export( + ethash_light_t light, + ethash_h256_t const *header_hash, + uint64_t nonce, + ethash_return_value_t *result) +{ + *result = ethash_light_compute(light, *header_hash, nonce); +} + +extern "C" MODULE_API ethash_full_t ethash_full_new_export(const char *dirname, ethash_light_t light, ethash_callback_t callback) +{ + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); + return ethash_full_new_internal(dirname, seedhash, full_size, light, callback); +} + +extern "C" MODULE_API void ethash_full_delete_export(ethash_full_t full) +{ + ethash_full_delete(full); +} + +extern "C" MODULE_API void ethash_full_compute_export( + ethash_full_t full, + ethash_h256_t const *header_hash, + uint64_t nonce, + ethash_return_value_t *result) +{ + *result = ethash_full_compute(full, *header_hash, nonce); +} + +extern "C" MODULE_API void const* ethash_full_dag_export(ethash_full_t full) +{ + return ethash_full_dag(full); +} + +extern "C" MODULE_API uint64_t ethash_full_dag_size_export(ethash_full_t full) +{ + return ethash_full_dag_size(full); +} + +extern "C" MODULE_API ethash_h256_t ethash_get_seedhash_export(uint64_t block_number) +{ + return ethash_get_seedhash(block_number); +} + +extern "C" MODULE_API bool ethash_get_default_dirname_export(char *buf, size_t buf_size) +{ + return ethash_get_default_dirname(buf, buf_size); +} \ No newline at end of file diff --git a/src/Native/libethhashb3/fnv.h b/src/Native/libethhashb3/fnv.h new file mode 100644 index 000000000..87217d9f3 --- /dev/null +++ b/src/Native/libethhashb3/fnv.h @@ -0,0 +1,43 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file fnv.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FNV_PRIME 0x01000193 + +/* The FNV-1 spec multiplies the prime with the input one byte (octet) in turn. + We instead multiply it with the full 32-bit input. + This gives a different result compared to a canonical FNV-1 implementation. +*/ +static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y) +{ + return x * FNV_PRIME ^ y; +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/internal.c b/src/Native/libethhashb3/internal.c new file mode 100644 index 000000000..1fc6858a0 --- /dev/null +++ b/src/Native/libethhashb3/internal.c @@ -0,0 +1,885 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file internal.c +* @author Tim Hughes +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#include +#include +#include +#include +#include +#include "mmap.h" +#include "ethash.h" +#include "fnv.h" +#include "endian.h" +#include "internal.h" +#include "data_sizes.h" +#include "io.h" +#include +#include + + +#define CHUNK_START 1 << 0 +#define CHUNK_END 1 << 1 +#define PARENT 1 << 2 +#define ROOT 1 << 3 +#define KEYED_HASH 1 << 4 +#define DERIVE_KEY_CONTEXT 1 << 5 +#define DERIVE_KEY_MATERIAL 1 << 6 + +#ifdef WITH_CRYPTOPP + +#include "sha3_cryptopp.h" + +#else +#include "sha3.h" +#endif // WITH_CRYPTOPP + +uint64_t ethash_get_datasize(uint64_t const block_number) +{ + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return dag_sizes[block_number / ETHASH_EPOCH_LENGTH]; +} + +uint64_t ethash_get_cachesize(uint64_t const block_number) +{ + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return cache_sizes[block_number / ETHASH_EPOCH_LENGTH]; +} + +// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) +// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf +// SeqMemoHash(s, R, N) +bool static ethash_compute_cache_nodes( + node* const nodes, + uint64_t cache_size, + ethash_h256_t const* seed +) +{ + if (cache_size % sizeof(node) != 0) { + return false; + } + uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node)); + + SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32); + + for (uint32_t i = 1; i != num_nodes; ++i) { + SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64); + } + + for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) { + for (uint32_t i = 0; i != num_nodes; i++) { + uint32_t const idx = nodes[i].words[0] % num_nodes; + node data; + data = nodes[(num_nodes - 1 + i) % num_nodes]; + for (uint32_t w = 0; w != NODE_WORDS; ++w) { + data.words[w] ^= nodes[idx].words[w]; + } + SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); + } + } + + // now perform endian conversion + fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS); + return true; +} + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const light +) +{ + uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node)); + node const* cache_nodes = (node const *) light->cache; + node const* init = &cache_nodes[node_index % num_parent_nodes]; + memcpy(ret, init, sizeof(node)); + ret->words[0] ^= node_index; + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +#if defined(_M_X64) && ENABLE_SSE + __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = ret->xmm[0]; + __m128i xmm1 = ret->xmm[1]; + __m128i xmm2 = ret->xmm[2]; + __m128i xmm3 = ret->xmm[3]; +#endif + + for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) { + uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes; + node const *parent = &cache_nodes[parent_index]; + +#if defined(_M_X64) && ENABLE_SSE + { + xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); + xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); + xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); + xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); + xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); + xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); + xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); + xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); + + // have to write to ret as values are used to compute index + ret->xmm[0] = xmm0; + ret->xmm[1] = xmm1; + ret->xmm[2] = xmm2; + ret->xmm[3] = xmm3; + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); + } + } +#endif + } + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +} + +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 || + (full_size % sizeof(node)) != 0) { + return false; + } + uint32_t const max_n = (uint32_t)(full_size / sizeof(node)); + node* full_nodes = mem; + double const progress_change = 1.0f / max_n; + double progress = 0.0f; + // now compute full nodes + for (uint32_t n = 0; n != max_n; ++n) { + if (callback && + n % (max_n / 100) == 0 && + callback((unsigned int)(ceil(progress * 100.0f))) != 0) { + + return false; + } + progress += progress_change; + ethash_calculate_dag_item(&(full_nodes[n]), n, light); + } + return true; +} + +static bool ethash_hash( + ethash_return_value_t* ret, + node const* full_nodes, + ethash_light_t const light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t const nonce +) +{ + if (full_size % MIX_WORDS != 0) { + return false; + } + + // pack hash and nonce together into first 40 bytes of s_mix + assert(sizeof(node) * 8 == 512); + node s_mix[MIX_NODES + 1]; + memcpy(s_mix[0].bytes, &header_hash, 32); + fix_endian64(s_mix[0].double_words[4], nonce); + + // compute sha3-512 hash and replicate across mix + blake3_hash_512(s_mix->bytes, s_mix->bytes, 40); + fix_endian_arr32(s_mix[0].words, 16); + + node* const mix = s_mix + 1; + for (uint32_t w = 0; w != MIX_WORDS; ++w) { + mix->words[w] = s_mix[0].words[w % NODE_WORDS]; + } + + unsigned const page_size = sizeof(uint32_t) * MIX_WORDS; + unsigned const num_full_pages = (unsigned) (full_size / page_size); + + for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) { + uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages; + + for (unsigned n = 0; n != MIX_NODES; ++n) { + node const* dag_node; + if (full_nodes) { + dag_node = &full_nodes[MIX_NODES * index + n]; + } else { + node tmp_node; + ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light); + dag_node = &tmp_node; + } + +#if defined(_M_X64) && ENABLE_SSE + { + __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); + __m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]); + __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]); + __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]); + mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]); + mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]); + mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]); + mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]); + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]); + } + } +#endif + } + + } + + // compress mix + for (uint32_t w = 0; w != MIX_WORDS; w += 4) { + uint32_t reduction = mix->words[w + 0]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 1]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 2]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 3]; + mix->words[w / 4] = reduction; + } + + fix_endian_arr32(mix->words, MIX_WORDS / 4); + memcpy(&ret->mix_hash, mix->bytes, 32); + // final Keccak hash + blake3_hash_256(s_mix->bytes, (uint8_t*)&ret->result, 64 + 32); // Keccak-256(s + compressed_mix) + return true; +} + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + uint64_t nonce, + ethash_h256_t const* mix_hash +) +{ + uint8_t buf[64 + 32]; + memcpy(buf, header_hash, 32); + fix_endian64_same(nonce); + memcpy(&(buf[32]), &nonce, 8); + SHA3_512(buf, buf, 40); + memcpy(&(buf[64]), mix_hash, 32); + SHA3_256(return_hash, buf, 64 + 32); +} + +ethash_h256_t ethash_get_seedhash(uint64_t block_number) +{ + ethash_h256_t ret; + ethash_h256_reset(&ret); + uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH; + for (uint32_t i = 0; i < epochs; ++i) + SHA3_256(&ret, (uint8_t*)&ret, 32); + return ret; +} + +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +) +{ + + ethash_h256_t return_hash; + ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash); + return ethash_check_difficulty(&return_hash, boundary); +} + +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed) +{ + struct ethash_light *ret; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->cache = malloc((size_t)cache_size); + if (!ret->cache) { + goto fail_free_light; + } + node* nodes = (node*)ret->cache; + if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) { + goto fail_free_cache_mem; + } + ret->cache_size = cache_size; + return ret; + +fail_free_cache_mem: + free(ret->cache); +fail_free_light: + free(ret); + return NULL; +} + +ethash_light_t ethash_light_new(uint64_t block_number) +{ + ethash_h256_t seedhash = ethash_get_seedhash(block_number); + ethash_light_t ret; + ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash); + ret->block_number = block_number; + return ret; +} + +void ethash_light_delete(ethash_light_t light) +{ + if (light->cache) { + free(light->cache); + } + free(light); +} + +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) { + ret.success = false; + } + return ret; +} + +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + uint64_t full_size = ethash_get_datasize(light->block_number); + return ethash_light_compute_internal(light, full_size, header_hash, nonce); +} + +static bool ethash_mmap(struct ethash_full* ret, FILE* f) +{ + int fd; + char* mmapped_data; + errno = 0; + ret->file = f; + if ((fd = ethash_fileno(ret->file)) == -1) { + return false; + } + mmapped_data= mmap( + NULL, + (size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0 + ); + if (mmapped_data == MAP_FAILED) { + return false; + } + ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE); + return true; +} + +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + struct ethash_full* ret; + FILE *f = NULL; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->file_size = (size_t)full_size; + switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) { + case ETHASH_IO_FAIL: + // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case + goto fail_free_full; + case ETHASH_IO_MEMO_MATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + return ret; + case ETHASH_IO_MEMO_SIZE_MISMATCH: + // if a DAG of same filename but unexpected size is found, silently force new file creation + if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) { + ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size."); + goto fail_free_full; + } + // fallthrough to the mismatch case here, DO NOT go through match + case ETHASH_IO_MEMO_MISMATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + break; + } + + if (!ethash_compute_full_data(ret->data, full_size, light, callback)) { + ETHASH_CRITICAL("Failure at computing DAG data."); + goto fail_free_full_data; + } + + // after the DAG has been filled then we finalize it by writting the magic number at the beginning + if (fseek(f, 0, SEEK_SET) != 0) { + ETHASH_CRITICAL("Could not seek to DAG file start to write magic number."); + goto fail_free_full_data; + } + uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM; + if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + ETHASH_CRITICAL("Could not write magic number to DAG's beginning."); + goto fail_free_full_data; + } + if (fflush(f) != 0) {// make sure the magic number IS there + ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?"); + goto fail_free_full_data; + } + return ret; + +fail_free_full_data: + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(ret->data, (size_t)full_size); +fail_close_file: + fclose(ret->file); +fail_free_full: + free(ret); + return NULL; +} + +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback) +{ + char strbuf[256]; + if (!ethash_get_default_dirname(strbuf, 256)) { + return NULL; + } + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); + return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback); +} + +void ethash_full_delete(ethash_full_t full) +{ + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(full->data, (size_t)full->file_size); + if (full->file) { + fclose(full->file); + } + free(full); +} + +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash( + &ret, + (node const*)full->data, + NULL, + full->file_size, + header_hash, + nonce)) { + ret.success = false; + } + return ret; +} + +void const* ethash_full_dag(ethash_full_t full) +{ + return full->data; +} + +uint64_t ethash_full_dag_size(ethash_full_t full) +{ + return full->file_size; +} + +static uint32_t IV[8] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +}; + +static size_t MSG_PERMUTATION[16] = {2, 6, 3, 10, 7, 0, 4, 13, + 1, 11, 12, 5, 9, 14, 15, 8}; + +inline static uint32_t rotate_right(uint32_t x, int n) { +return (x >> n) | (x << (32 - n)); +} + +// The mixing function, G, which mixes either a column or a diagonal. +inline static void g(uint32_t state[16], size_t a, size_t b, size_t c, size_t d, + uint32_t mx, uint32_t my) { + state[a] = state[a] + state[b] + mx; + state[d] = rotate_right(state[d] ^ state[a], 16); + state[c] = state[c] + state[d]; + state[b] = rotate_right(state[b] ^ state[c], 12); + state[a] = state[a] + state[b] + my; + state[d] = rotate_right(state[d] ^ state[a], 8); + state[c] = state[c] + state[d]; + state[b] = rotate_right(state[b] ^ state[c], 7); +} + +inline static void round_function(uint32_t state[16], uint32_t m[16]) { + // Mix the columns. + g(state, 0, 4, 8, 12, m[0], m[1]); + g(state, 1, 5, 9, 13, m[2], m[3]); + g(state, 2, 6, 10, 14, m[4], m[5]); + g(state, 3, 7, 11, 15, m[6], m[7]); + // Mix the diagonals. + g(state, 0, 5, 10, 15, m[8], m[9]); + g(state, 1, 6, 11, 12, m[10], m[11]); + g(state, 2, 7, 8, 13, m[12], m[13]); + g(state, 3, 4, 9, 14, m[14], m[15]); +} + +inline static void permute(uint32_t m[16]) { + uint32_t permuted[16]; + for (size_t i = 0; i < 16; i++) { + permuted[i] = m[MSG_PERMUTATION[i]]; + } + memcpy(m, permuted, sizeof(permuted)); +} + +inline static void compress(const uint32_t chaining_value[8], + const uint32_t block_words[16], uint64_t counter, + uint32_t block_len, uint32_t flags, + uint32_t out[16]) { + uint32_t state[16] = { + chaining_value[0], + chaining_value[1], + chaining_value[2], + chaining_value[3], + chaining_value[4], + chaining_value[5], + chaining_value[6], + chaining_value[7], + IV[0], + IV[1], + IV[2], + IV[3], + (uint32_t)counter, + (uint32_t)(counter >> 32), + block_len, + flags, + }; + uint32_t block[16]; + memcpy(block, block_words, sizeof(block)); + + round_function(state, block); // round 1 + permute(block); + round_function(state, block); // round 2 + permute(block); + round_function(state, block); // round 3 + permute(block); + round_function(state, block); // round 4 + permute(block); + round_function(state, block); // round 5 + permute(block); + round_function(state, block); // round 6 + permute(block); + round_function(state, block); // round 7 + + for (size_t i = 0; i < 8; i++) { + state[i] ^= state[i + 8]; + state[i + 8] ^= chaining_value[i]; + } + + memcpy(out, state, sizeof(state)); +} + +inline static void words_from_little_endian_bytes(const void *bytes, + size_t bytes_len, + uint32_t *out) { + assert(bytes_len % 4 == 0); + const uint8_t *u8_ptr = (const uint8_t *)bytes; + for (size_t i = 0; i < (bytes_len / 4); i++) { + out[i] = ((uint32_t)(*u8_ptr++)); + out[i] += ((uint32_t)(*u8_ptr++)) << 8; + out[i] += ((uint32_t)(*u8_ptr++)) << 16; + out[i] += ((uint32_t)(*u8_ptr++)) << 24; + } +} + +// Each chunk or parent node can produce either an 8-word chaining value or, by +// setting the ROOT flag, any number of final output bytes. The Output struct +// captures the state just prior to choosing between those two possibilities. +typedef struct output { + uint32_t input_chaining_value[8]; + uint32_t block_words[16]; + uint64_t counter; + uint32_t block_len; + uint32_t flags; +} output; + +inline static void output_chaining_value(const output *self, uint32_t out[8]) { + uint32_t out16[16]; + compress(self->input_chaining_value, self->block_words, self->counter, + self->block_len, self->flags, out16); + memcpy(out, out16, 8 * 4); +} + +inline static void output_root_bytes(const output *self, void *out, + size_t out_len) { + uint8_t *out_u8 = (uint8_t *)out; + uint64_t output_block_counter = 0; + while (out_len > 0) { + uint32_t words[16]; + compress(self->input_chaining_value, self->block_words, + output_block_counter, self->block_len, self->flags | ROOT, words); + for (size_t word = 0; word < 16; word++) { + for (int byte = 0; byte < 4; byte++) { + if (out_len == 0) { + return; + } + *out_u8 = (uint8_t)(words[word] >> (8 * byte)); + out_u8++; + out_len--; + } + } + output_block_counter++; + } +} + +inline static void chunk_state_init(_blake3_chunk_state *self, + const uint32_t key_words[8], + uint64_t chunk_counter, uint32_t flags) { + memcpy(self->chaining_value, key_words, sizeof(self->chaining_value)); + self->chunk_counter = chunk_counter; + memset(self->block, 0, sizeof(self->block)); + self->block_len = 0; + self->blocks_compressed = 0; + self->flags = flags; +} + +inline static size_t chunk_state_len(const _blake3_chunk_state *self) { + return BLAKE3_BLOCK_LEN * (size_t)self->blocks_compressed + + (size_t)self->block_len; +} + +inline static uint32_t chunk_state_start_flag(const _blake3_chunk_state *self) { + if (self->blocks_compressed == 0) { + return CHUNK_START; + } else { + return 0; + } +} + +inline static void chunk_state_update(_blake3_chunk_state *self, + const void *input, size_t input_len) { + const uint8_t *input_u8 = (const uint8_t *)input; + while (input_len > 0) { + // If the block buffer is full, compress it and clear it. More input is + // coming, so this compression is not CHUNK_END. + if (self->block_len == BLAKE3_BLOCK_LEN) { + uint32_t block_words[16]; + words_from_little_endian_bytes(self->block, BLAKE3_BLOCK_LEN, + block_words); + uint32_t out16[16]; + compress(self->chaining_value, block_words, self->chunk_counter, + BLAKE3_BLOCK_LEN, self->flags | chunk_state_start_flag(self), + out16); + memcpy(self->chaining_value, out16, sizeof(self->chaining_value)); + self->blocks_compressed++; + memset(self->block, 0, sizeof(self->block)); + self->block_len = 0; + } + + // Copy input bytes into the block buffer. + size_t want = BLAKE3_BLOCK_LEN - (size_t)self->block_len; + size_t take = want; + if (input_len < want) { + take = input_len; + } + memcpy(&self->block[(size_t)self->block_len], input_u8, take); + self->block_len += (uint8_t)take; + input_u8 += take; + input_len -= take; + } +} + +inline static output chunk_state_output(const _blake3_chunk_state *self) { + output ret; + memcpy(ret.input_chaining_value, self->chaining_value, + sizeof(ret.input_chaining_value)); + words_from_little_endian_bytes(self->block, sizeof(self->block), + ret.block_words); + ret.counter = self->chunk_counter; + ret.block_len = (uint32_t)self->block_len; + ret.flags = self->flags | chunk_state_start_flag(self) | CHUNK_END; + return ret; +} + +inline static output parent_output(const uint32_t left_child_cv[8], + const uint32_t right_child_cv[8], + const uint32_t key_words[8], + uint32_t flags) { + output ret; + memcpy(ret.input_chaining_value, key_words, sizeof(ret.input_chaining_value)); + memcpy(&ret.block_words[0], left_child_cv, 8 * 4); + memcpy(&ret.block_words[8], right_child_cv, 8 * 4); + ret.counter = 0; // Always 0 for parent nodes. + ret.block_len = + BLAKE3_BLOCK_LEN; // Always BLAKE3_BLOCK_LEN (64) for parent nodes. + ret.flags = PARENT | flags; + return ret; +} + +inline static void parent_cv(const uint32_t left_child_cv[8], + const uint32_t right_child_cv[8], + const uint32_t key_words[8], uint32_t flags, + uint32_t out[8]) { + output o = parent_output(left_child_cv, right_child_cv, key_words, flags); + // We only write to `out` after we've read the inputs. That makes it safe for + // `out` to alias an input, which we do below. + output_chaining_value(&o, out); +} + +inline static void hasher_init_internal(blake3_hasher *self, + const uint32_t key_words[8], + uint32_t flags) { + chunk_state_init(&self->chunk_state, key_words, 0, flags); + memcpy(self->key_words, key_words, sizeof(self->key_words)); + self->cv_stack_len = 0; + self->flags = flags; +} + +// Construct a new `Hasher` for the regular hash function. +void blake3_hasher_init(blake3_hasher *self) { + hasher_init_internal(self, IV, 0); +} + +// Construct a new `Hasher` for the keyed hash function. +void blake3_hasher_init_keyed(blake3_hasher *self, + const uint8_t key[BLAKE3_KEY_LEN]) { + uint32_t key_words[8]; + words_from_little_endian_bytes(key, BLAKE3_KEY_LEN, key_words); + hasher_init_internal(self, key_words, KEYED_HASH); +} + +// Construct a new `Hasher` for the key derivation function. The context +// string should be hardcoded, globally unique, and application-specific. +void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context) { + blake3_hasher context_hasher; + hasher_init_internal(&context_hasher, IV, DERIVE_KEY_CONTEXT); + blake3_hasher_update(&context_hasher, context, strlen(context)); + uint8_t context_key[BLAKE3_KEY_LEN]; + blake3_hasher_finalize(&context_hasher, context_key, BLAKE3_KEY_LEN); + uint32_t context_key_words[8]; + words_from_little_endian_bytes(context_key, BLAKE3_KEY_LEN, + context_key_words); + hasher_init_internal(self, context_key_words, DERIVE_KEY_MATERIAL); +} + +inline static void hasher_push_stack(blake3_hasher *self, + const uint32_t cv[8]) { + memcpy(&self->cv_stack[(size_t)self->cv_stack_len * 8], cv, 8 * 4); + self->cv_stack_len++; +} + +// Returns a pointer to the popped CV, which is valid until the next push. +inline static const uint32_t *hasher_pop_stack(blake3_hasher *self) { +self->cv_stack_len--; +return &self->cv_stack[(size_t)self->cv_stack_len * 8]; +} + +// Section 5.1.2 of the BLAKE3 spec explains this algorithm in more detail. +inline static void hasher_add_chunk_cv(blake3_hasher *self, uint32_t new_cv[8], + uint64_t total_chunks) { + // This chunk might complete some subtrees. For each completed subtree, its + // left child will be the current top entry in the CV stack, and its right + // child will be the current value of `new_cv`. Pop each left child off the + // stack, merge it with `new_cv`, and overwrite `new_cv` with the result. + // After all these merges, push the final value of `new_cv` onto the stack. + // The number of completed subtrees is given by the number of trailing 0-bits + // in the new total number of chunks. + while ((total_chunks & 1) == 0) { + parent_cv(hasher_pop_stack(self), new_cv, self->key_words, self->flags, + new_cv); + total_chunks >>= 1; + } + hasher_push_stack(self, new_cv); +} + +// Add input to the hash state. This can be called any number of times. +void blake3_hasher_update(blake3_hasher *self, const void *input, + size_t input_len) { + const uint8_t *input_u8 = (const uint8_t *)input; + while (input_len > 0) { + // If the current chunk is complete, finalize it and reset the chunk state. + // More input is coming, so this chunk is not ROOT. + if (chunk_state_len(&self->chunk_state) == BLAKE3_CHUNK_LEN) { + output chunk_output = chunk_state_output(&self->chunk_state); + uint32_t chunk_cv[8]; + output_chaining_value(&chunk_output, chunk_cv); + uint64_t total_chunks = self->chunk_state.chunk_counter + 1; + hasher_add_chunk_cv(self, chunk_cv, total_chunks); + chunk_state_init(&self->chunk_state, self->key_words, total_chunks, + self->flags); + } + + // Compress input bytes into the current chunk state. + size_t want = BLAKE3_CHUNK_LEN - chunk_state_len(&self->chunk_state); + size_t take = want; + if (input_len < want) { + take = input_len; + } + chunk_state_update(&self->chunk_state, input_u8, take); + input_u8 += take; + input_len -= take; + } +} + +// Finalize the hash and write any number of output bytes. +void blake3_hasher_finalize(const blake3_hasher *self, void *out, + size_t out_len) { + // Starting with the output from the current chunk, compute all the parent + // chaining values along the right edge of the tree, until we have the root + // output. + output current_output = chunk_state_output(&self->chunk_state); + size_t parent_nodes_remaining = (size_t)self->cv_stack_len; + while (parent_nodes_remaining > 0) { + parent_nodes_remaining--; + uint32_t current_cv[8]; + output_chaining_value(¤t_output, current_cv); + current_output = parent_output(&self->cv_stack[parent_nodes_remaining * 8], + current_cv, self->key_words, self->flags); + } + output_root_bytes(¤t_output, out, out_len); +} + +void blake3_hash_256(const uint8_t *input, uint8_t *out, size_t len) { + blake3_hasher hasher; + blake3_hasher_init(&hasher); + blake3_hasher_update(&hasher, input, len); + blake3_hasher_finalize(&hasher, out, 32); +} + +void blake3_hash_512(const uint8_t *input, uint8_t *out, size_t len) { + blake3_hasher hasher; + blake3_hasher_init(&hasher); + blake3_hasher_update(&hasher, input, len); + blake3_hasher_finalize(&hasher, out, 64); +} \ No newline at end of file diff --git a/src/Native/libethhashb3/internal.h b/src/Native/libethhashb3/internal.h new file mode 100644 index 000000000..aa6f73fea --- /dev/null +++ b/src/Native/libethhashb3/internal.h @@ -0,0 +1,224 @@ +#pragma once +#include "compiler.h" +#include "endian.h" +#include "ethash.h" +#include + +#ifndef _BLAKE3_REFERENCE_IMPL_H +#define _BLAKE3_REFERENCE_IMPL_H + +#include +#include + +#define BLAKE3_OUT_LEN 32 +#define BLAKE3_KEY_LEN 32 +#define BLAKE3_BLOCK_LEN 64 +#define BLAKE3_CHUNK_LEN 1024 + + +#define ENABLE_SSE 0 + +#if defined(_M_X64) && ENABLE_SSE +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// compile time settings +#define NODE_WORDS (64/4) +#define MIX_WORDS (ETHASH_MIX_BYTES/4) +#define MIX_NODES (MIX_WORDS / NODE_WORDS) +#include + +typedef union node { + uint8_t bytes[NODE_WORDS * 4]; + uint32_t words[NODE_WORDS]; + uint64_t double_words[NODE_WORDS / 2]; + +#if defined(_M_X64) && ENABLE_SSE + __m128i xmm[NODE_WORDS/4]; +#endif + +} node; + +static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i) +{ + return hash->b[i]; +} + +static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v) +{ + hash->b[i] = v; +} + +static inline void ethash_h256_reset(ethash_h256_t* hash) +{ + memset(hash, 0, 32); +} + +// Returns if hash is less than or equal to boundary (2^256/difficulty) +static inline bool ethash_check_difficulty( + ethash_h256_t const* hash, + ethash_h256_t const* boundary +) +{ + // Boundary is big endian + for (int i = 0; i < 32; i++) { + if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) { + continue; + } + return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i); + } + return true; +} + +/** + * Difficulty quick check for POW preverification + * + * @param header_hash The hash of the header + * @param nonce The block's nonce + * @param mix_hash The mix digest hash + * @param boundary The boundary is defined as (2^256 / difficulty) + * @return true for succesful pre-verification and false otherwise + */ +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +); + +struct ethash_light { + void* cache; + uint64_t cache_size; + uint64_t block_number; +}; + +/** + * Allocate and initialize a new ethash_light handler. Internal version + * + * @param cache_size The size of the cache in bytes + * @param seed Block seedhash to be used during the computation of the + * cache nodes + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed); + +/** + * Calculate the light client data. Internal version. + * + * @param light The light client handler + * @param full_size The size of the full data in bytes. + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return The resulting hash. + */ +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +); + +struct ethash_full { + FILE* file; + uint64_t file_size; + node* data; +}; + +/** + * Allocate and initialize a new ethash_full handler. Internal version. + * + * @param dirname The directory in which to put the DAG file. + * @param seedhash The seed hash of the block. Used in the DAG file naming. + * @param full_size The size of the full data in bytes. + * @param cache A cache object to use that was allocated with @ref ethash_cache_new(). + * Iff this function succeeds the ethash_full_t will take memory + * memory ownership of the cache and free it at deletion. If + * not then the user still has to handle freeing of the cache himself. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const cache +); + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + const uint64_t nonce, + ethash_h256_t const* mix_hash +); + +uint64_t ethash_get_datasize(uint64_t const block_number); +uint64_t ethash_get_cachesize(uint64_t const block_number); + +/** + * Compute the memory data for a full node's memory + * + * @param mem A pointer to an ethash full's memory + * @param full_size The size of the full data in bytes + * @param cache A cache object to use in the calculation + * @param callback The callback function. Check @ref ethash_full_new() for details. + * @return true if all went fine and false for invalid parameters + */ +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +#ifdef __cplusplus +} +#endif + +// This struct is private. +typedef struct _blake3_chunk_state { + uint32_t chaining_value[8]; + uint64_t chunk_counter; + uint8_t block[BLAKE3_BLOCK_LEN]; + uint8_t block_len; + uint8_t blocks_compressed; + uint32_t flags; +} _blake3_chunk_state; + +// An incremental hasher that can accept any number of writes. +typedef struct blake3_hasher { + _blake3_chunk_state chunk_state; + uint32_t key_words[8]; + uint32_t cv_stack[8 * 54]; // Space for 54 subtree chaining values: + uint8_t cv_stack_len; // 2^54 * CHUNK_LEN = 2^64 + uint32_t flags; +} blake3_hasher; + +void blake3_hasher_init(blake3_hasher *self); +void blake3_hasher_init_keyed(blake3_hasher *self, + const uint8_t key[BLAKE3_KEY_LEN]); +void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context); +void blake3_hasher_update(blake3_hasher *self, const void *input, + size_t input_len); +void blake3_hasher_finalize(const blake3_hasher *self, void *out, + size_t out_len); + +void blake3_hash_512(const uint8_t *input, uint8_t *out, size_t len); +void blake3_hash_256(const uint8_t *input, uint8_t *out, size_t len); + +#endif // _BLAKE3_REFERENCE_IMPL_H \ No newline at end of file diff --git a/src/Native/libethhashb3/io.c b/src/Native/libethhashb3/io.c new file mode 100644 index 000000000..a0fa92fef --- /dev/null +++ b/src/Native/libethhashb3/io.c @@ -0,0 +1,119 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io.c + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "io.h" +#include +#include +#include + +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +) +{ + char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; + enum ethash_io_rc ret = ETHASH_IO_FAIL; + // reset errno before io calls + errno = 0; + + // assert directory exists + if (!ethash_mkdir(dirname)) { + ETHASH_CRITICAL("Could not create the ethash directory"); + goto end; + } + + ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name); + char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name)); + if (!tmpfile) { + ETHASH_CRITICAL("Could not create the full DAG pathname"); + goto end; + } + + FILE *f; + if (!force_create) { + // try to open the file + f = ethash_fopen(tmpfile, "rb+"); + if (f) { + size_t found_size; + if (!ethash_file_size(f, &found_size)) { + fclose(f); + ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile); + goto free_memo; + } + if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + // compare the magic number, no need to care about endianess since it's local + uint64_t magic_num; + if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + // I/O error + fclose(f); + ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + if (magic_num != ETHASH_DAG_MAGIC_NUM) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + ret = ETHASH_IO_MEMO_MATCH; + goto set_file; + } + } + + // file does not exist, will need to be created + f = ethash_fopen(tmpfile, "wb+"); + if (!f) { + ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile); + goto free_memo; + } + // make sure it's of the proper size + if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fputc('\n', f) == EOF) { + fclose(f); + ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fflush(f) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + ret = ETHASH_IO_MEMO_MISMATCH; + goto set_file; + + ret = ETHASH_IO_MEMO_MATCH; +set_file: + *output_file = f; +free_memo: + free(tmpfile); +end: + return ret; +} \ No newline at end of file diff --git a/src/Native/libethhashb3/io.h b/src/Native/libethhashb3/io.h new file mode 100644 index 000000000..378b9d0b7 --- /dev/null +++ b/src/Native/libethhashb3/io.h @@ -0,0 +1,202 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#include +#include +#include +#include +#ifdef __cplusplus +#define __STDC_FORMAT_MACROS 1 +#endif +#include +#include "endian.h" +#include "ethash.h" + +#ifdef __cplusplus +extern "C" { +#endif +// Maximum size for mutable part of DAG file name +// 6 is for "full-R", the suffix of the filename +// 10 is for maximum number of digits of a uint32_t (for REVISION) +// 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of +// the seedhash and last 1 is for the null terminating character +// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG +#define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1) +/// Possible return values of @see ethash_io_prepare +enum ethash_io_rc { + ETHASH_IO_FAIL = 0, ///< There has been an IO failure + ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong. + ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch + ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything +}; + +// small hack for windows. I don't feel I should use va_args and forward just +// to have this one function properly cross-platform abstracted +#if defined(_WIN32) && !defined(__GNUC__) +#define snprintf(...) sprintf_s(__VA_ARGS__) +#endif + +/** + * Logs a critical error in important parts of ethash. Should mostly help + * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL + * ethash_full_t + */ +#ifdef ETHASH_PRINT_CRITICAL_OUTPUT +#define ETHASH_CRITICAL(...) \ + do \ + { \ + printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define ETHASH_CRITICAL(...) +#endif + +/** + * Prepares io for ethash + * + * Create the DAG directory and the DAG file if they don't exist. + * + * @param[in] dirname A null terminated c-string of the path of the ethash + * data directory. If it does not exist it's created. + * @param[in] seedhash The seedhash of the current block number, used in the + * naming of the file as can be seen from the spec at: + * https://github.com/ethereum/wiki/wiki/Ethash-DAG + * @param[out] output_file If there was no failure then this will point to an open + * file descriptor. User is responsible for closing it. + * In the case of memo match then the file is open on read + * mode, while on the case of mismatch a new file is created + * on write mode + * @param[in] file_size The size that the DAG file should have on disk + * @param[out] force_create If true then there is no check to see if the file + * already exists + * @return For possible return values @see enum ethash_io_rc + */ +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +); + +/** + * An fopen wrapper for no-warnings crossplatform fopen. + * + * Msvc compiler considers fopen to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param file_name The path to the file to open + * @param mode Opening mode. Check fopen() + * @return The FILE* or NULL in failure + */ +FILE* ethash_fopen(char const* file_name, char const* mode); + +/** + * An strncat wrapper for no-warnings crossplatform strncat. + * + * Msvc compiler considers strncat to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param des Destination buffer + * @param dest_size Maximum size of the destination buffer. This is the + * extra argument for the MSVC secure strncat + * @param src Souce buffer + * @param count Number of bytes to copy from source + * @return If all is well returns the dest buffer. If there is an + * error returns NULL + */ +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count); + +/** + * A cross-platform mkdir wrapper to create a directory or assert it's there + * + * @param dirname The full path of the directory to create + * @return true if the directory was created or if it already + * existed + */ +bool ethash_mkdir(char const* dirname); + +/** + * Get a file's size + * + * @param[in] f The open file stream whose size to get + * @param[out] size Pass a size_t by reference to contain the file size + * @return true in success and false if there was a failure + */ +bool ethash_file_size(FILE* f, size_t* ret_size); + +/** + * Get a file descriptor number from a FILE stream + * + * @param f The file stream whose fd to get + * @return Platform specific fd handler + */ +int ethash_fileno(FILE* f); + +/** + * Create the filename for the DAG. + * + * @param dirname The directory name in which the DAG file should reside + * If it does not end with a directory separator it is appended. + * @param filename The actual name of the file + * @param filename_length The length of the filename in bytes + * @return A char* containing the full name. User must deallocate. + */ +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +); + +/** + * Gets the default directory name for the DAG depending on the system + * + * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG + * + * @param[out] strbuf A string buffer of sufficient size to keep the + * null termninated string of the directory name + * @param[in] buffsize Size of @a strbuf in bytes + * @return true for success and false otherwise + */ +bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + +static inline bool ethash_io_mutable_name( + uint32_t revision, + ethash_h256_t const* seed_hash, + char* output +) +{ + uint64_t hash = *((uint64_t*)seed_hash); +#if LITTLE_ENDIAN == BYTE_ORDER + hash = ethash_swap_u64(hash); +#endif + return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0; +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/io_posix.c b/src/Native/libethhashb3/io_posix.c new file mode 100644 index 000000000..4d6aa28e4 --- /dev/null +++ b/src/Native/libethhashb3/io_posix.c @@ -0,0 +1,111 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io_posix.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + return fopen(file_name, mode); +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE *f) +{ + return fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "/", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ + struct stat st; + int fd; + if ((fd = fileno(f)) == -1 || fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = ".Ethash-B3/"; + strbuf[0] = '\0'; + char* home_dir = getenv("HOME"); + if (!home_dir || strlen(home_dir) == 0) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd) + home_dir = pwd->pw_dir; + } + + size_t len = strlen(home_dir); + if (!ethash_strncat(strbuf, buffsize, home_dir, len)) { + return false; + } + if (home_dir[len] != '/') { + if (!ethash_strncat(strbuf, buffsize, "/", 1)) { + return false; + } + } + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} \ No newline at end of file diff --git a/src/Native/libethhashb3/io_win32.c b/src/Native/libethhashb3/io_win32.c new file mode 100644 index 000000000..bd7d563e2 --- /dev/null +++ b/src/Native/libethhashb3/io_win32.c @@ -0,0 +1,100 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io_win32.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + FILE* f; + return fopen_s(&f, file_name, mode) == 0 ? f : NULL; +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = _mkdir(dirname); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE* f) +{ + return _fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "\\", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ + struct _stat st; + int fd; + if ((fd = _fileno(f)) == -1 || _fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = "Ethash\\"; + strbuf[0] = '\0'; + if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) { + return false; + } + if (!ethash_strncat(strbuf, buffsize, "\\", 1)) { + return false; + } + + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} \ No newline at end of file diff --git a/src/Native/libethhashb3/libethhashb3.sln b/src/Native/libethhashb3/libethhashb3.sln new file mode 100644 index 000000000..5166f5b97 --- /dev/null +++ b/src/Native/libethhashb3/libethhashb3.sln @@ -0,0 +1,31 @@ + +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}") = "libmultihash", "libethhashb3.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {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 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libethhashb3/libethhashb3.vcxproj b/src/Native/libethhashb3/libethhashb3.vcxproj new file mode 100644 index 000000000..bf1883a5f --- /dev/null +++ b/src/Native/libethhashb3/libethhashb3.vcxproj @@ -0,0 +1,202 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libethhashb3 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libethhash\windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libethhashb3/mmap.h b/src/Native/libethhashb3/mmap.h new file mode 100644 index 000000000..d18bad395 --- /dev/null +++ b/src/Native/libethhashb3/mmap.h @@ -0,0 +1,45 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file mmap.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#if defined(__MINGW32__) || defined(_WIN32) +#include + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +/* This flag is only available in WinXP+ */ +#ifdef FILE_MAP_EXECUTE +#define PROT_EXEC 0x4 +#else +#define PROT_EXEC 0x0 +#define FILE_MAP_EXECUTE 0 +#endif + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset); +void munmap(void* addr, size_t length); +#else // posix, yay! ^_^ +#include +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/mmap_win32.c b/src/Native/libethhashb3/mmap_win32.c new file mode 100644 index 000000000..b022eba4f --- /dev/null +++ b/src/Native/libethhashb3/mmap_win32.c @@ -0,0 +1,84 @@ +/* mmap() replacement for Windows + * + * Author: Mike Frysinger + * Placed into the public domain + */ + +/* References: + * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx + * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx + * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx + * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx + */ + +#include +#include +#include "mmap.h" + +#ifdef __USE_FILE_OFFSET64 +# define DWORD_HI(x) (x >> 32) +# define DWORD_LO(x) ((x) & 0xffffffff) +#else +# define DWORD_HI(x) (0) +# define DWORD_LO(x) (x) +#endif + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset) +{ + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return MAP_FAILED; + if (fd == -1) { + if (!(flags & MAP_ANON) || offset) + return MAP_FAILED; + } else if (flags & MAP_ANON) + return MAP_FAILED; + + DWORD flProtect; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_READWRITE; + } else if (prot & PROT_EXEC) { + if (prot & PROT_READ) + flProtect = PAGE_EXECUTE_READ; + else if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE; + } else + flProtect = PAGE_READONLY; + + off_t end = length + offset; + HANDLE mmap_fd, h; + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else + mmap_fd = (HANDLE)_get_osfhandle(fd); + h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL); + if (h == NULL) + return MAP_FAILED; + + DWORD dwDesiredAccess; + if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else + dwDesiredAccess = FILE_MAP_READ; + if (prot & PROT_EXEC) + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; + void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); + if (ret == NULL) { + ret = MAP_FAILED; + } + // since we are handling the file ourselves with fd, close the Windows Handle here + CloseHandle(h); + return ret; +} + +void munmap(void* addr, size_t length) +{ + UnmapViewOfFile(addr); +} + +#undef DWORD_HI +#undef DWORD_LO \ No newline at end of file diff --git a/src/Native/libethhashb3/sha3.c b/src/Native/libethhashb3/sha3.c new file mode 100644 index 000000000..c79f93af1 --- /dev/null +++ b/src/Native/libethhashb3/sha3.c @@ -0,0 +1,151 @@ +/** libkeccak-tiny +* +* A single-file implementation of SHA-3 and SHAKE. +* +* Implementor: David Leon Gil +* License: CC0, attribution kindly requested. Blame taken too, +* but not liability. +*/ +#include "sha3.h" + +#include +#include +#include +#include + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset(a, 0, 200); + return 0; +} + +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ + } + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(256) +defsha3(512) \ No newline at end of file diff --git a/src/Native/libethhashb3/sha3.h b/src/Native/libethhashb3/sha3.h new file mode 100644 index 000000000..6b933bf64 --- /dev/null +++ b/src/Native/libethhashb3/sha3.h @@ -0,0 +1,31 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "compiler.h" +#include +#include + +struct ethash_h256; + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, uint8_t const*, size_t); + +decsha3(256) +decsha3(512) + +static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const size) +{ + sha3_256((uint8_t*)ret, 32, data, size); +} + +static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size) +{ + sha3_512(ret, 64, data, size); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/sha3_cryptopp.cpp b/src/Native/libethhashb3/sha3_cryptopp.cpp new file mode 100644 index 000000000..03e8a892e --- /dev/null +++ b/src/Native/libethhashb3/sha3_cryptopp.cpp @@ -0,0 +1,37 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ + +/** @file sha3.cpp +* @author Tim Hughes +* @date 2015 +*/ +#include +#include + +extern "C" { +struct ethash_h256; +typedef struct ethash_h256 ethash_h256_t; +void SHA3_256(ethash_h256_t const* ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size); +} + +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_512().CalculateDigest(ret, data, size); +} +} \ No newline at end of file diff --git a/src/Native/libethhashb3/sha3_cryptopp.h b/src/Native/libethhashb3/sha3_cryptopp.h new file mode 100644 index 000000000..63048fcc7 --- /dev/null +++ b/src/Native/libethhashb3/sha3_cryptopp.h @@ -0,0 +1,18 @@ +#pragma once + +#include "compiler.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ethash_h256; + +void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size); +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/stdafx.cpp b/src/Native/libethhashb3/stdafx.cpp new file mode 100644 index 000000000..636b815d0 --- /dev/null +++ b/src/Native/libethhashb3/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// $safeprojectname$.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file \ No newline at end of file diff --git a/src/Native/libethhashb3/stdafx.h b/src/Native/libethhashb3/stdafx.h new file mode 100644 index 000000000..9ecb4d644 --- /dev/null +++ b/src/Native/libethhashb3/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + + + +// TODO: reference additional headers your program requires here \ No newline at end of file diff --git a/src/Native/libethhashb3/stdint.h b/src/Native/libethhashb3/stdint.h new file mode 100644 index 000000000..96a20e1e3 --- /dev/null +++ b/src/Native/libethhashb3/stdint.h @@ -0,0 +1,259 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] \ No newline at end of file diff --git a/src/Native/libethhashb3/targetver.h b/src/Native/libethhashb3/targetver.h new file mode 100644 index 000000000..5b1f29cad --- /dev/null +++ b/src/Native/libethhashb3/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include \ No newline at end of file diff --git a/src/Native/libethhashb3/util.h b/src/Native/libethhashb3/util.h new file mode 100644 index 000000000..34df2c638 --- /dev/null +++ b/src/Native/libethhashb3/util.h @@ -0,0 +1,47 @@ +/* + This file is part of ethash. + + ethash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file util.h + * @author Tim Hughes + * @date 2015 + */ +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +void debugf(char const* str, ...); +#else +#define debugf printf +#endif + +static inline uint32_t min_u32(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} + +static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_) +{ + return x < min_ ? min_ : (x > max_ ? max_ : x); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/Native/libethhashb3/util_win32.c b/src/Native/libethhashb3/util_win32.c new file mode 100644 index 000000000..59693b96e --- /dev/null +++ b/src/Native/libethhashb3/util_win32.c @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file util.c + * @author Tim Hughes + * @date 2015 + */ +#include +#include +#include "util.h" + + +// foward declare without all of Windows.h +__declspec(dllimport) void __stdcall OutputDebugStringA(char const* lpOutputString); + +void debugf(char const* str, ...) +{ + va_list args; + va_start(args, str); + + char buf[1<<16]; + _vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args); + buf[sizeof(buf)-1] = '\0'; + OutputDebugStringA(buf); +} \ No newline at end of file diff --git a/src/Native/libmultihash/Makefile b/src/Native/libmultihash/Makefile index 9b4099bf0..c3940e43d 100644 --- a/src/Native/libmultihash/Makefile +++ b/src/Native/libmultihash/Makefile @@ -12,8 +12,10 @@ OBJECTS = bcrypt.o blake.o c11.o dcrypt.o fresh.o lane.o \ sha3/sph_luffa.o sha3/sph_shabal.o sha3/sph_shavite.o sha3/sph_simd.o sha3/sph_skein.o sha3/sph_whirlpool.o \ sha3/sph_haval.o sha3/sph_sha2.o sha3/sph_sha2big.o sha3/sm3.o sha3/panama.o \ sha3/extra.o sha3/gost_streebog.o sha3/sph_tiger.o sha3/SWIFFTX.o KeccakP-800-reference.o \ - shavite3.o skein.o x11.o x13.o x15.o x17.o x16r.o x16rv2.o x16s.o x21s.o x22i.o \ + shavite3.o skein.o skein2.o x11.o x13.o x15.o x17.o x16r.o x16rv2.o x16s.o x21s.o x22i.o \ blake2/sse/blake2s.o blake2/sse/blake2b.o \ + blake3/blake3.o blake3/blake3_dispatch.o blake3/blake3_portable.o \ + blake3/blake3_sse41_x86-64_unix.o blake3/blake3_avx2_x86-64_unix.o blake3/blake3_avx512_x86-64_unix.o \ Lyra2.o Lyra2RE.o Sponge.o geek.o \ heavyhash/heavyhash.o heavyhash/keccak_tiny.o \ verthash/tiny_sha3/sha3.o verthash/h2.o \ @@ -22,6 +24,8 @@ OBJECTS = bcrypt.o blake.o c11.o dcrypt.o fresh.o lane.o \ equi/crypto/sha1.o equi/crypto/sha512.o equi/crypto/sha256.o \ equi/crypto/hmac_sha256.o equi/crypto/equihash.o equi/crypto/ripemd160.o \ equi/equihashverify.o sha512_256.o sha256dt.o \ + skydoge.o yescrypt/sha256.o yescrypt/yescrypt.o yescrypt/yescrypt-opt.o \ + yespower/crypto/blake2b-yp.o yespower/yespower-blake2b.o yespower/yespower-combined.o yespower/yespower-platform.o \ minotaur/crypto/sha256.o minotaur/crypto/yespower.o minotaur/minotaurx.o all: $(TARGET) diff --git a/src/Native/libmultihash/allium.c b/src/Native/libmultihash/allium.c new file mode 100644 index 000000000..e8663db89 --- /dev/null +++ b/src/Native/libmultihash/allium.c @@ -0,0 +1,46 @@ +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_cubehash.h" + +#include "Lyra2.h" + +void allium_hash(const char* input, char* output, uint32_t len) +{ + uint32_t hashA[8], hashB[8]; + + sph_blake256_context ctx_blake; + sph_keccak256_context ctx_keccak; + sph_cubehash512_context ctx_cubehash; + sph_skein256_context ctx_skein; + sph_groestl256_context ctx_groestl; + + sph_blake256_init(&ctx_blake); + sph_blake256(&ctx_blake, input, len); + sph_blake256_close(&ctx_blake, hashA); + + sph_keccak256_init(&ctx_keccak); + sph_keccak256(&ctx_keccak, hashA, 32); + sph_keccak256_close(&ctx_keccak, hashB); + + LYRA2(hashA, 32, hashB, 32, hashB, 32, 1, 8, 8); + + sph_cubehash256_init(&ctx_cubehash); + sph_cubehash256(&ctx_cubehash, hashA, 32); + sph_cubehash256_close(&ctx_cubehash, hashB); + + LYRA2(hashA, 32, hashB, 32, hashB, 32, 1, 8, 8); + + sph_skein256_init(&ctx_skein); + sph_skein256(&ctx_skein, hashA, 32); + sph_skein256_close(&ctx_skein, hashB); + + sph_groestl256_init(&ctx_groestl); + sph_groestl256(&ctx_groestl, hashB, 32); + sph_groestl256_close(&ctx_groestl, hashA); + + memcpy(output, hashA, 32); +} diff --git a/src/Native/libmultihash/allium.h b/src/Native/libmultihash/allium.h new file mode 100644 index 000000000..3705161f7 --- /dev/null +++ b/src/Native/libmultihash/allium.h @@ -0,0 +1,16 @@ +#ifndef ALLIUM_H +#define ALLIUM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void allium_hash(const char* input, char* output, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Native/libmultihash/blake3/blake3.c b/src/Native/libmultihash/blake3/blake3.c new file mode 100644 index 000000000..b1e8f5be8 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3.c @@ -0,0 +1,610 @@ +#include +#include +#include + +#include "blake3.h" +#include "blake3_impl.h" + +INLINE void chunk_state_init(blake3_chunk_state *self, const uint32_t key[8], + uint8_t flags) { + memcpy(self->cv, key, BLAKE3_KEY_LEN); + self->chunk_counter = 0; + memset(self->buf, 0, BLAKE3_BLOCK_LEN); + self->buf_len = 0; + self->blocks_compressed = 0; + self->flags = flags; +} + +INLINE void chunk_state_reset(blake3_chunk_state *self, const uint32_t key[8], + uint64_t chunk_counter) { + memcpy(self->cv, key, BLAKE3_KEY_LEN); + self->chunk_counter = chunk_counter; + self->blocks_compressed = 0; + memset(self->buf, 0, BLAKE3_BLOCK_LEN); + self->buf_len = 0; +} + +INLINE size_t chunk_state_len(const blake3_chunk_state *self) { + return (BLAKE3_BLOCK_LEN * (size_t)self->blocks_compressed) + + ((size_t)self->buf_len); +} + +INLINE size_t chunk_state_fill_buf(blake3_chunk_state *self, + const uint8_t *input, size_t input_len) { + size_t take = BLAKE3_BLOCK_LEN - ((size_t)self->buf_len); + if (take > input_len) { + take = input_len; + } + uint8_t *dest = self->buf + ((size_t)self->buf_len); + memcpy(dest, input, take); + self->buf_len += (uint8_t)take; + return take; +} + +INLINE uint8_t chunk_state_maybe_start_flag(const blake3_chunk_state *self) { + if (self->blocks_compressed == 0) { + return CHUNK_START; + } else { + return 0; + } +} + +typedef struct { + uint32_t input_cv[8]; + uint64_t counter; + uint8_t block[BLAKE3_BLOCK_LEN]; + uint8_t block_len; + uint8_t flags; +} output_t; + +INLINE output_t make_output(const uint32_t input_cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags) { + output_t ret; + memcpy(ret.input_cv, input_cv, 32); + memcpy(ret.block, block, BLAKE3_BLOCK_LEN); + ret.block_len = block_len; + ret.counter = counter; + ret.flags = flags; + return ret; +} + +// Chaining values within a given chunk (specifically the compress_in_place +// interface) are represented as words. This avoids unnecessary bytes<->words +// conversion overhead in the portable implementation. However, the hash_many +// interface handles both user input and parent node blocks, so it accepts +// bytes. For that reason, chaining values in the CV stack are represented as +// bytes. +INLINE void output_chaining_value(const output_t *self, uint8_t cv[32]) { + uint32_t cv_words[8]; + memcpy(cv_words, self->input_cv, 32); + blake3_compress_in_place(cv_words, self->block, self->block_len, + self->counter, self->flags); + memcpy(cv, cv_words, 32); +} + +INLINE void output_root_bytes(const output_t *self, uint64_t seek, uint8_t *out, + size_t out_len) { + uint64_t output_block_counter = seek / 64; + size_t offset_within_block = seek % 64; + uint8_t wide_buf[64]; + while (out_len > 0) { + blake3_compress_xof(self->input_cv, self->block, self->block_len, + output_block_counter, self->flags | ROOT, wide_buf); + size_t available_bytes = 64 - offset_within_block; + size_t memcpy_len; + if (out_len > available_bytes) { + memcpy_len = available_bytes; + } else { + memcpy_len = out_len; + } + memcpy(out, wide_buf + offset_within_block, memcpy_len); + out += memcpy_len; + out_len -= memcpy_len; + output_block_counter += 1; + offset_within_block = 0; + } +} + +INLINE void chunk_state_update(blake3_chunk_state *self, const uint8_t *input, + size_t input_len) { + if (self->buf_len > 0) { + size_t take = chunk_state_fill_buf(self, input, input_len); + input += take; + input_len -= take; + if (input_len > 0) { + blake3_compress_in_place( + self->cv, self->buf, BLAKE3_BLOCK_LEN, self->chunk_counter, + self->flags | chunk_state_maybe_start_flag(self)); + self->blocks_compressed += 1; + self->buf_len = 0; + memset(self->buf, 0, BLAKE3_BLOCK_LEN); + } + } + + while (input_len > BLAKE3_BLOCK_LEN) { + blake3_compress_in_place(self->cv, input, BLAKE3_BLOCK_LEN, + self->chunk_counter, + self->flags | chunk_state_maybe_start_flag(self)); + self->blocks_compressed += 1; + input += BLAKE3_BLOCK_LEN; + input_len -= BLAKE3_BLOCK_LEN; + } + + size_t take = chunk_state_fill_buf(self, input, input_len); + input += take; + input_len -= take; +} + +INLINE output_t chunk_state_output(const blake3_chunk_state *self) { + uint8_t block_flags = + self->flags | chunk_state_maybe_start_flag(self) | CHUNK_END; + return make_output(self->cv, self->buf, self->buf_len, self->chunk_counter, + block_flags); +} + +INLINE output_t parent_output(const uint8_t block[BLAKE3_BLOCK_LEN], + const uint32_t key[8], uint8_t flags) { + return make_output(key, block, BLAKE3_BLOCK_LEN, 0, flags | PARENT); +} + +// Given some input larger than one chunk, return the number of bytes that +// should go in the left subtree. This is the largest power-of-2 number of +// chunks that leaves at least 1 byte for the right subtree. +INLINE size_t left_len(size_t content_len) { + // Subtract 1 to reserve at least one byte for the right side. content_len + // should always be greater than BLAKE3_CHUNK_LEN. + size_t full_chunks = (content_len - 1) / BLAKE3_CHUNK_LEN; + return round_down_to_power_of_2(full_chunks) * BLAKE3_CHUNK_LEN; +} + +// Use SIMD parallelism to hash up to MAX_SIMD_DEGREE chunks at the same time +// on a single thread. Write out the chunk chaining values and return the +// number of chunks hashed. These chunks are never the root and never empty; +// those cases use a different codepath. +INLINE size_t compress_chunks_parallel(const uint8_t *input, size_t input_len, + const uint32_t key[8], + uint64_t chunk_counter, uint8_t flags, + uint8_t *out) { +#if defined(BLAKE3_TESTING) + assert(0 < input_len); + assert(input_len <= MAX_SIMD_DEGREE * BLAKE3_CHUNK_LEN); +#endif + + const uint8_t *chunks_array[MAX_SIMD_DEGREE]; + size_t input_position = 0; + size_t chunks_array_len = 0; + while (input_len - input_position >= BLAKE3_CHUNK_LEN) { + chunks_array[chunks_array_len] = &input[input_position]; + input_position += BLAKE3_CHUNK_LEN; + chunks_array_len += 1; + } + + blake3_hash_many(chunks_array, chunks_array_len, + BLAKE3_CHUNK_LEN / BLAKE3_BLOCK_LEN, key, chunk_counter, + true, flags, CHUNK_START, CHUNK_END, out); + + // Hash the remaining partial chunk, if there is one. Note that the empty + // chunk (meaning the empty message) is a different codepath. + if (input_len > input_position) { + uint64_t counter = chunk_counter + (uint64_t)chunks_array_len; + blake3_chunk_state chunk_state; + chunk_state_init(&chunk_state, key, flags); + chunk_state.chunk_counter = counter; + chunk_state_update(&chunk_state, &input[input_position], + input_len - input_position); + output_t output = chunk_state_output(&chunk_state); + output_chaining_value(&output, &out[chunks_array_len * BLAKE3_OUT_LEN]); + return chunks_array_len + 1; + } else { + return chunks_array_len; + } +} + +// Use SIMD parallelism to hash up to MAX_SIMD_DEGREE parents at the same time +// on a single thread. Write out the parent chaining values and return the +// number of parents hashed. (If there's an odd input chaining value left over, +// return it as an additional output.) These parents are never the root and +// never empty; those cases use a different codepath. +INLINE size_t compress_parents_parallel(const uint8_t *child_chaining_values, + size_t num_chaining_values, + const uint32_t key[8], uint8_t flags, + uint8_t *out) { +#if defined(BLAKE3_TESTING) + assert(2 <= num_chaining_values); + assert(num_chaining_values <= 2 * MAX_SIMD_DEGREE_OR_2); +#endif + + const uint8_t *parents_array[MAX_SIMD_DEGREE_OR_2]; + size_t parents_array_len = 0; + while (num_chaining_values - (2 * parents_array_len) >= 2) { + parents_array[parents_array_len] = + &child_chaining_values[2 * parents_array_len * BLAKE3_OUT_LEN]; + parents_array_len += 1; + } + + blake3_hash_many(parents_array, parents_array_len, 1, key, + 0, // Parents always use counter 0. + false, flags | PARENT, + 0, // Parents have no start flags. + 0, // Parents have no end flags. + out); + + // If there's an odd child left over, it becomes an output. + if (num_chaining_values > 2 * parents_array_len) { + memcpy(&out[parents_array_len * BLAKE3_OUT_LEN], + &child_chaining_values[2 * parents_array_len * BLAKE3_OUT_LEN], + BLAKE3_OUT_LEN); + return parents_array_len + 1; + } else { + return parents_array_len; + } +} + +// The wide helper function returns (writes out) an array of chaining values +// and returns the length of that array. The number of chaining values returned +// is the dyanmically detected SIMD degree, at most MAX_SIMD_DEGREE. Or fewer, +// if the input is shorter than that many chunks. The reason for maintaining a +// wide array of chaining values going back up the tree, is to allow the +// implementation to hash as many parents in parallel as possible. +// +// As a special case when the SIMD degree is 1, this function will still return +// at least 2 outputs. This guarantees that this function doesn't perform the +// root compression. (If it did, it would use the wrong flags, and also we +// wouldn't be able to implement exendable ouput.) Note that this function is +// not used when the whole input is only 1 chunk long; that's a different +// codepath. +// +// Why not just have the caller split the input on the first update(), instead +// of implementing this special rule? Because we don't want to limit SIMD or +// multi-threading parallelism for that update(). +static size_t blake3_compress_subtree_wide(const uint8_t *input, + size_t input_len, + const uint32_t key[8], + uint64_t chunk_counter, + uint8_t flags, uint8_t *out) { + // Note that the single chunk case does *not* bump the SIMD degree up to 2 + // when it is 1. If this implementation adds multi-threading in the future, + // this gives us the option of multi-threading even the 2-chunk case, which + // can help performance on smaller platforms. + if (input_len <= blake3_simd_degree() * BLAKE3_CHUNK_LEN) { + return compress_chunks_parallel(input, input_len, key, chunk_counter, flags, + out); + } + + // With more than simd_degree chunks, we need to recurse. Start by dividing + // the input into left and right subtrees. (Note that this is only optimal + // as long as the SIMD degree is a power of 2. If we ever get a SIMD degree + // of 3 or something, we'll need a more complicated strategy.) + size_t left_input_len = left_len(input_len); + size_t right_input_len = input_len - left_input_len; + const uint8_t *right_input = &input[left_input_len]; + uint64_t right_chunk_counter = + chunk_counter + (uint64_t)(left_input_len / BLAKE3_CHUNK_LEN); + + // Make space for the child outputs. Here we use MAX_SIMD_DEGREE_OR_2 to + // account for the special case of returning 2 outputs when the SIMD degree + // is 1. + uint8_t cv_array[2 * MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; + size_t degree = blake3_simd_degree(); + if (left_input_len > BLAKE3_CHUNK_LEN && degree == 1) { + // The special case: We always use a degree of at least two, to make + // sure there are two outputs. Except, as noted above, at the chunk + // level, where we allow degree=1. (Note that the 1-chunk-input case is + // a different codepath.) + degree = 2; + } + uint8_t *right_cvs = &cv_array[degree * BLAKE3_OUT_LEN]; + + // Recurse! If this implementation adds multi-threading support in the + // future, this is where it will go. + size_t left_n = blake3_compress_subtree_wide(input, left_input_len, key, + chunk_counter, flags, cv_array); + size_t right_n = blake3_compress_subtree_wide( + right_input, right_input_len, key, right_chunk_counter, flags, right_cvs); + + // The special case again. If simd_degree=1, then we'll have left_n=1 and + // right_n=1. Rather than compressing them into a single output, return + // them directly, to make sure we always have at least two outputs. + if (left_n == 1) { + memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); + return 2; + } + + // Otherwise, do one layer of parent node compression. + size_t num_chaining_values = left_n + right_n; + return compress_parents_parallel(cv_array, num_chaining_values, key, flags, + out); +} + +// Hash a subtree with compress_subtree_wide(), and then condense the resulting +// list of chaining values down to a single parent node. Don't compress that +// last parent node, however. Instead, return its message bytes (the +// concatenated chaining values of its children). This is necessary when the +// first call to update() supplies a complete subtree, because the topmost +// parent node of that subtree could end up being the root. It's also necessary +// for extended output in the general case. +// +// As with compress_subtree_wide(), this function is not used on inputs of 1 +// chunk or less. That's a different codepath. +INLINE void compress_subtree_to_parent_node( + const uint8_t *input, size_t input_len, const uint32_t key[8], + uint64_t chunk_counter, uint8_t flags, uint8_t out[2 * BLAKE3_OUT_LEN]) { +#if defined(BLAKE3_TESTING) + assert(input_len > BLAKE3_CHUNK_LEN); +#endif + + uint8_t cv_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; + size_t num_cvs = blake3_compress_subtree_wide(input, input_len, key, + chunk_counter, flags, cv_array); + + // If MAX_SIMD_DEGREE is greater than 2 and there's enough input, + // compress_subtree_wide() returns more than 2 chaining values. Condense + // them into 2 by forming parent nodes repeatedly. + uint8_t out_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN / 2]; + while (num_cvs > 2) { + num_cvs = + compress_parents_parallel(cv_array, num_cvs, key, flags, out_array); + memcpy(cv_array, out_array, num_cvs * BLAKE3_OUT_LEN); + } + memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); +} + +INLINE void hasher_init_base(blake3_hasher *self, const uint32_t key[8], + uint8_t flags) { + memcpy(self->key, key, BLAKE3_KEY_LEN); + chunk_state_init(&self->chunk, key, flags); + self->cv_stack_len = 0; +} + +void blake3_hasher_init(blake3_hasher *self) { hasher_init_base(self, IV, 0); } + +void blake3_hasher_init_keyed(blake3_hasher *self, + const uint8_t key[BLAKE3_KEY_LEN]) { + uint32_t key_words[8]; + load_key_words(key, key_words); + hasher_init_base(self, key_words, KEYED_HASH); +} + +void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context) { + blake3_hasher context_hasher; + hasher_init_base(&context_hasher, IV, DERIVE_KEY_CONTEXT); + blake3_hasher_update(&context_hasher, context, strlen(context)); + uint8_t context_key[BLAKE3_KEY_LEN]; + blake3_hasher_finalize(&context_hasher, context_key, BLAKE3_KEY_LEN); + uint32_t context_key_words[8]; + load_key_words(context_key, context_key_words); + hasher_init_base(self, context_key_words, DERIVE_KEY_MATERIAL); +} + +// As described in hasher_push_cv() below, we do "lazy merging", delaying +// merges until right before the next CV is about to be added. This is +// different from the reference implementation. Another difference is that we +// aren't always merging 1 chunk at a time. Instead, each CV might represent +// any power-of-two number of chunks, as long as the smaller-above-larger stack +// order is maintained. Instead of the "count the trailing 0-bits" algorithm +// described in the spec, we use a "count the total number of 1-bits" variant +// that doesn't require us to retain the subtree size of the CV on top of the +// stack. The principle is the same: each CV that should remain in the stack is +// represented by a 1-bit in the total number of chunks (or bytes) so far. +INLINE void hasher_merge_cv_stack(blake3_hasher *self, uint64_t total_len) { + size_t post_merge_stack_len = (size_t)popcnt(total_len); + while (self->cv_stack_len > post_merge_stack_len) { + uint8_t *parent_node = + &self->cv_stack[(self->cv_stack_len - 2) * BLAKE3_OUT_LEN]; + output_t output = parent_output(parent_node, self->key, self->chunk.flags); + output_chaining_value(&output, parent_node); + self->cv_stack_len -= 1; + } +} + +// In reference_impl.rs, we merge the new CV with existing CVs from the stack +// before pushing it. We can do that because we know more input is coming, so +// we know none of the merges are root. +// +// This setting is different. We want to feed as much input as possible to +// compress_subtree_wide(), without setting aside anything for the chunk_state. +// If the user gives us 64 KiB, we want to parallelize over all 64 KiB at once +// as a single subtree, if at all possible. +// +// This leads to two problems: +// 1) This 64 KiB input might be the only call that ever gets made to update. +// In this case, the root node of the 64 KiB subtree would be the root node +// of the whole tree, and it would need to be ROOT finalized. We can't +// compress it until we know. +// 2) This 64 KiB input might complete a larger tree, whose root node is +// similarly going to be the the root of the whole tree. For example, maybe +// we have 196 KiB (that is, 128 + 64) hashed so far. We can't compress the +// node at the root of the 256 KiB subtree until we know how to finalize it. +// +// The second problem is solved with "lazy merging". That is, when we're about +// to add a CV to the stack, we don't merge it with anything first, as the +// reference impl does. Instead we do merges using the *previous* CV that was +// added, which is sitting on top of the stack, and we put the new CV +// (unmerged) on top of the stack afterwards. This guarantees that we never +// merge the root node until finalize(). +// +// Solving the first problem requires an additional tool, +// compress_subtree_to_parent_node(). That function always returns the top +// *two* chaining values of the subtree it's compressing. We then do lazy +// merging with each of them separately, so that the second CV will always +// remain unmerged. (That also helps us support extendable output when we're +// hashing an input all-at-once.) +INLINE void hasher_push_cv(blake3_hasher *self, uint8_t new_cv[BLAKE3_OUT_LEN], + uint64_t chunk_counter) { + hasher_merge_cv_stack(self, chunk_counter); + memcpy(&self->cv_stack[self->cv_stack_len * BLAKE3_OUT_LEN], new_cv, + BLAKE3_OUT_LEN); + self->cv_stack_len += 1; +} + +void blake3_hasher_update(blake3_hasher *self, const void *input, + size_t input_len) { + // Explicitly checking for zero avoids causing UB by passing a null pointer + // to memcpy. This comes up in practice with things like: + // std::vector v; + // blake3_hasher_update(&hasher, v.data(), v.size()); + if (input_len == 0) { + return; + } + + const uint8_t *input_bytes = (const uint8_t *)input; + + // If we have some partial chunk bytes in the internal chunk_state, we need + // to finish that chunk first. + if (chunk_state_len(&self->chunk) > 0) { + size_t take = BLAKE3_CHUNK_LEN - chunk_state_len(&self->chunk); + if (take > input_len) { + take = input_len; + } + chunk_state_update(&self->chunk, input_bytes, take); + input_bytes += take; + input_len -= take; + // If we've filled the current chunk and there's more coming, finalize this + // chunk and proceed. In this case we know it's not the root. + if (input_len > 0) { + output_t output = chunk_state_output(&self->chunk); + uint8_t chunk_cv[32]; + output_chaining_value(&output, chunk_cv); + hasher_push_cv(self, chunk_cv, self->chunk.chunk_counter); + chunk_state_reset(&self->chunk, self->key, self->chunk.chunk_counter + 1); + } else { + return; + } + } + + // Now the chunk_state is clear, and we have more input. If there's more than + // a single chunk (so, definitely not the root chunk), hash the largest whole + // subtree we can, with the full benefits of SIMD (and maybe in the future, + // multi-threading) parallelism. Two restrictions: + // - The subtree has to be a power-of-2 number of chunks. Only subtrees along + // the right edge can be incomplete, and we don't know where the right edge + // is going to be until we get to finalize(). + // - The subtree must evenly divide the total number of chunks up until this + // point (if total is not 0). If the current incomplete subtree is only + // waiting for 1 more chunk, we can't hash a subtree of 4 chunks. We have + // to complete the current subtree first. + // Because we might need to break up the input to form powers of 2, or to + // evenly divide what we already have, this part runs in a loop. + while (input_len > BLAKE3_CHUNK_LEN) { + size_t subtree_len = round_down_to_power_of_2(input_len); + uint64_t count_so_far = self->chunk.chunk_counter * BLAKE3_CHUNK_LEN; + // Shrink the subtree_len until it evenly divides the count so far. We know + // that subtree_len itself is a power of 2, so we can use a bitmasking + // trick instead of an actual remainder operation. (Note that if the caller + // consistently passes power-of-2 inputs of the same size, as is hopefully + // typical, this loop condition will always fail, and subtree_len will + // always be the full length of the input.) + // + // An aside: We don't have to shrink subtree_len quite this much. For + // example, if count_so_far is 1, we could pass 2 chunks to + // compress_subtree_to_parent_node. Since we'll get 2 CVs back, we'll still + // get the right answer in the end, and we might get to use 2-way SIMD + // parallelism. The problem with this optimization, is that it gets us + // stuck always hashing 2 chunks. The total number of chunks will remain + // odd, and we'll never graduate to higher degrees of parallelism. See + // https://github.com/BLAKE3-team/BLAKE3/issues/69. + while ((((uint64_t)(subtree_len - 1)) & count_so_far) != 0) { + subtree_len /= 2; + } + // The shrunken subtree_len might now be 1 chunk long. If so, hash that one + // chunk by itself. Otherwise, compress the subtree into a pair of CVs. + uint64_t subtree_chunks = subtree_len / BLAKE3_CHUNK_LEN; + if (subtree_len <= BLAKE3_CHUNK_LEN) { + blake3_chunk_state chunk_state; + chunk_state_init(&chunk_state, self->key, self->chunk.flags); + chunk_state.chunk_counter = self->chunk.chunk_counter; + chunk_state_update(&chunk_state, input_bytes, subtree_len); + output_t output = chunk_state_output(&chunk_state); + uint8_t cv[BLAKE3_OUT_LEN]; + output_chaining_value(&output, cv); + hasher_push_cv(self, cv, chunk_state.chunk_counter); + } else { + // This is the high-performance happy path, though getting here depends + // on the caller giving us a long enough input. + uint8_t cv_pair[2 * BLAKE3_OUT_LEN]; + compress_subtree_to_parent_node(input_bytes, subtree_len, self->key, + self->chunk.chunk_counter, + self->chunk.flags, cv_pair); + hasher_push_cv(self, cv_pair, self->chunk.chunk_counter); + hasher_push_cv(self, &cv_pair[BLAKE3_OUT_LEN], + self->chunk.chunk_counter + (subtree_chunks / 2)); + } + self->chunk.chunk_counter += subtree_chunks; + input_bytes += subtree_len; + input_len -= subtree_len; + } + + // If there's any remaining input less than a full chunk, add it to the chunk + // state. In that case, also do a final merge loop to make sure the subtree + // stack doesn't contain any unmerged pairs. The remaining input means we + // know these merges are non-root. This merge loop isn't strictly necessary + // here, because hasher_push_chunk_cv already does its own merge loop, but it + // simplifies blake3_hasher_finalize below. + if (input_len > 0) { + chunk_state_update(&self->chunk, input_bytes, input_len); + hasher_merge_cv_stack(self, self->chunk.chunk_counter); + } +} + +void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, + size_t out_len) { + blake3_hasher_finalize_seek(self, 0, out, out_len); +} + +void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, + uint8_t *out, size_t out_len) { + // Explicitly checking for zero avoids causing UB by passing a null pointer + // to memcpy. This comes up in practice with things like: + // std::vector v; + // blake3_hasher_finalize(&hasher, v.data(), v.size()); + if (out_len == 0) { + return; + } + + // If the subtree stack is empty, then the current chunk is the root. + if (self->cv_stack_len == 0) { + output_t output = chunk_state_output(&self->chunk); + output_root_bytes(&output, seek, out, out_len); + return; + } + // If there are any bytes in the chunk state, finalize that chunk and do a + // roll-up merge between that chunk hash and every subtree in the stack. In + // this case, the extra merge loop at the end of blake3_hasher_update + // guarantees that none of the subtrees in the stack need to be merged with + // each other first. Otherwise, if there are no bytes in the chunk state, + // then the top of the stack is a chunk hash, and we start the merge from + // that. + output_t output; + size_t cvs_remaining; + if (chunk_state_len(&self->chunk) > 0) { + cvs_remaining = self->cv_stack_len; + output = chunk_state_output(&self->chunk); + } else { + // There are always at least 2 CVs in the stack in this case. + cvs_remaining = self->cv_stack_len - 2; + output = parent_output(&self->cv_stack[cvs_remaining * 32], self->key, + self->chunk.flags); + } + while (cvs_remaining > 0) { + cvs_remaining -= 1; + uint8_t parent_block[BLAKE3_BLOCK_LEN]; + memcpy(parent_block, &self->cv_stack[cvs_remaining * 32], 32); + output_chaining_value(&output, &parent_block[32]); + output = parent_output(parent_block, self->key, self->chunk.flags); + } + output_root_bytes(&output, seek, out, out_len); +} + +void blake3_hash(const char *input, char *output, size_t input_len) +{ + // Initialize the hasher. + blake3_hasher hasher; + blake3_hasher_init(&hasher); + + blake3_hasher_update(&hasher, input, input_len); + + // Finalize the hash. BLAKE3_OUT_LEN is the default output length, 32 bytes. + blake3_hasher_finalize(&hasher, (uint8_t *)output, BLAKE3_OUT_LEN); +} diff --git a/src/Native/libmultihash/blake3/blake3.h b/src/Native/libmultihash/blake3/blake3.h new file mode 100644 index 000000000..48796ff09 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3.h @@ -0,0 +1,58 @@ +#ifndef BLAKE3_H +#define BLAKE3_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLAKE3_KEY_LEN 32 +#define BLAKE3_OUT_LEN 32 +#define BLAKE3_BLOCK_LEN 64 +#define BLAKE3_CHUNK_LEN 1024 +#define BLAKE3_MAX_DEPTH 54 +#define BLAKE3_MAX_SIMD_DEGREE 16 + +// This struct is a private implementation detail. It has to be here because +// it's part of blake3_hasher below. +typedef struct { + uint32_t cv[8]; + uint64_t chunk_counter; + uint8_t buf[BLAKE3_BLOCK_LEN]; + uint8_t buf_len; + uint8_t blocks_compressed; + uint8_t flags; +} blake3_chunk_state; + +typedef struct { + uint32_t key[8]; + blake3_chunk_state chunk; + uint8_t cv_stack_len; + // The stack size is MAX_DEPTH + 1 because we do lazy merging. For example, + // with 7 chunks, we have 3 entries in the stack. Adding an 8th chunk + // requires a 4th entry, rather than merging everything down to 1, because we + // don't know whether more input is coming. This is different from how the + // reference implementation does things. + uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN]; +} blake3_hasher; + +void blake3_hasher_init(blake3_hasher *self); +void blake3_hasher_init_keyed(blake3_hasher *self, + const uint8_t key[BLAKE3_KEY_LEN]); +void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context); +void blake3_hasher_update(blake3_hasher *self, const void *input, + size_t input_len); +void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, + size_t out_len); +void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, + uint8_t *out, size_t out_len); + +void blake3_hash(const char* input, char* output, size_t input_len); + +#ifdef __cplusplus +} +#endif + +#endif /* BLAKE3_H */ diff --git a/src/Native/libmultihash/blake3/blake3_avx2.c b/src/Native/libmultihash/blake3/blake3_avx2.c new file mode 100644 index 000000000..c5a2ce9e2 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx2.c @@ -0,0 +1,325 @@ +#include "blake3_impl.h" + +#include + +#define DEGREE 8 + +INLINE __m256i loadu(const uint8_t src[32]) { + return _mm256_loadu_si256((const __m256i *)src); +} + +INLINE void storeu(__m256i src, uint8_t dest[16]) { + _mm256_storeu_si256((__m256i *)dest, src); +} + +INLINE __m256i addv(__m256i a, __m256i b) { return _mm256_add_epi32(a, b); } + +// Note that clang-format doesn't like the name "xor" for some reason. +INLINE __m256i xorv(__m256i a, __m256i b) { return _mm256_xor_si256(a, b); } + +INLINE __m256i set1(uint32_t x) { return _mm256_set1_epi32((int32_t)x); } + +INLINE __m256i rot16(__m256i x) { + return _mm256_shuffle_epi8( + x, _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, + 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2)); +} + +INLINE __m256i rot12(__m256i x) { + return _mm256_or_si256(_mm256_srli_epi32(x, 12), _mm256_slli_epi32(x, 32 - 12)); +} + +INLINE __m256i rot8(__m256i x) { + return _mm256_shuffle_epi8( + x, _mm256_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1, + 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1)); +} + +INLINE __m256i rot7(__m256i x) { + return _mm256_or_si256(_mm256_srli_epi32(x, 7), _mm256_slli_epi32(x, 32 - 7)); +} + +INLINE void round_fn(__m256i v[16], __m256i m[16], size_t r) { + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); + v[0] = addv(v[0], v[4]); + v[1] = addv(v[1], v[5]); + v[2] = addv(v[2], v[6]); + v[3] = addv(v[3], v[7]); + v[12] = xorv(v[12], v[0]); + v[13] = xorv(v[13], v[1]); + v[14] = xorv(v[14], v[2]); + v[15] = xorv(v[15], v[3]); + v[12] = rot16(v[12]); + v[13] = rot16(v[13]); + v[14] = rot16(v[14]); + v[15] = rot16(v[15]); + v[8] = addv(v[8], v[12]); + v[9] = addv(v[9], v[13]); + v[10] = addv(v[10], v[14]); + v[11] = addv(v[11], v[15]); + v[4] = xorv(v[4], v[8]); + v[5] = xorv(v[5], v[9]); + v[6] = xorv(v[6], v[10]); + v[7] = xorv(v[7], v[11]); + v[4] = rot12(v[4]); + v[5] = rot12(v[5]); + v[6] = rot12(v[6]); + v[7] = rot12(v[7]); + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); + v[0] = addv(v[0], v[4]); + v[1] = addv(v[1], v[5]); + v[2] = addv(v[2], v[6]); + v[3] = addv(v[3], v[7]); + v[12] = xorv(v[12], v[0]); + v[13] = xorv(v[13], v[1]); + v[14] = xorv(v[14], v[2]); + v[15] = xorv(v[15], v[3]); + v[12] = rot8(v[12]); + v[13] = rot8(v[13]); + v[14] = rot8(v[14]); + v[15] = rot8(v[15]); + v[8] = addv(v[8], v[12]); + v[9] = addv(v[9], v[13]); + v[10] = addv(v[10], v[14]); + v[11] = addv(v[11], v[15]); + v[4] = xorv(v[4], v[8]); + v[5] = xorv(v[5], v[9]); + v[6] = xorv(v[6], v[10]); + v[7] = xorv(v[7], v[11]); + v[4] = rot7(v[4]); + v[5] = rot7(v[5]); + v[6] = rot7(v[6]); + v[7] = rot7(v[7]); + + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); + v[0] = addv(v[0], v[5]); + v[1] = addv(v[1], v[6]); + v[2] = addv(v[2], v[7]); + v[3] = addv(v[3], v[4]); + v[15] = xorv(v[15], v[0]); + v[12] = xorv(v[12], v[1]); + v[13] = xorv(v[13], v[2]); + v[14] = xorv(v[14], v[3]); + v[15] = rot16(v[15]); + v[12] = rot16(v[12]); + v[13] = rot16(v[13]); + v[14] = rot16(v[14]); + v[10] = addv(v[10], v[15]); + v[11] = addv(v[11], v[12]); + v[8] = addv(v[8], v[13]); + v[9] = addv(v[9], v[14]); + v[5] = xorv(v[5], v[10]); + v[6] = xorv(v[6], v[11]); + v[7] = xorv(v[7], v[8]); + v[4] = xorv(v[4], v[9]); + v[5] = rot12(v[5]); + v[6] = rot12(v[6]); + v[7] = rot12(v[7]); + v[4] = rot12(v[4]); + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); + v[0] = addv(v[0], v[5]); + v[1] = addv(v[1], v[6]); + v[2] = addv(v[2], v[7]); + v[3] = addv(v[3], v[4]); + v[15] = xorv(v[15], v[0]); + v[12] = xorv(v[12], v[1]); + v[13] = xorv(v[13], v[2]); + v[14] = xorv(v[14], v[3]); + v[15] = rot8(v[15]); + v[12] = rot8(v[12]); + v[13] = rot8(v[13]); + v[14] = rot8(v[14]); + v[10] = addv(v[10], v[15]); + v[11] = addv(v[11], v[12]); + v[8] = addv(v[8], v[13]); + v[9] = addv(v[9], v[14]); + v[5] = xorv(v[5], v[10]); + v[6] = xorv(v[6], v[11]); + v[7] = xorv(v[7], v[8]); + v[4] = xorv(v[4], v[9]); + v[5] = rot7(v[5]); + v[6] = rot7(v[6]); + v[7] = rot7(v[7]); + v[4] = rot7(v[4]); +} + +INLINE void transpose_vecs(__m256i vecs[DEGREE]) { + // Interleave 32-bit lanes. The low unpack is lanes 00/11/44/55, and the high + // is 22/33/66/77. + __m256i ab_0145 = _mm256_unpacklo_epi32(vecs[0], vecs[1]); + __m256i ab_2367 = _mm256_unpackhi_epi32(vecs[0], vecs[1]); + __m256i cd_0145 = _mm256_unpacklo_epi32(vecs[2], vecs[3]); + __m256i cd_2367 = _mm256_unpackhi_epi32(vecs[2], vecs[3]); + __m256i ef_0145 = _mm256_unpacklo_epi32(vecs[4], vecs[5]); + __m256i ef_2367 = _mm256_unpackhi_epi32(vecs[4], vecs[5]); + __m256i gh_0145 = _mm256_unpacklo_epi32(vecs[6], vecs[7]); + __m256i gh_2367 = _mm256_unpackhi_epi32(vecs[6], vecs[7]); + + // Interleave 64-bit lates. The low unpack is lanes 00/22 and the high is + // 11/33. + __m256i abcd_04 = _mm256_unpacklo_epi64(ab_0145, cd_0145); + __m256i abcd_15 = _mm256_unpackhi_epi64(ab_0145, cd_0145); + __m256i abcd_26 = _mm256_unpacklo_epi64(ab_2367, cd_2367); + __m256i abcd_37 = _mm256_unpackhi_epi64(ab_2367, cd_2367); + __m256i efgh_04 = _mm256_unpacklo_epi64(ef_0145, gh_0145); + __m256i efgh_15 = _mm256_unpackhi_epi64(ef_0145, gh_0145); + __m256i efgh_26 = _mm256_unpacklo_epi64(ef_2367, gh_2367); + __m256i efgh_37 = _mm256_unpackhi_epi64(ef_2367, gh_2367); + + // Interleave 128-bit lanes. + vecs[0] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x20); + vecs[1] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x20); + vecs[2] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x20); + vecs[3] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x20); + vecs[4] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x31); + vecs[5] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x31); + vecs[6] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x31); + vecs[7] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x31); +} + +INLINE void transpose_msg_vecs(const uint8_t *const *inputs, + size_t block_offset, __m256i out[16]) { + out[0] = loadu(&inputs[0][block_offset + 0 * sizeof(__m256i)]); + out[1] = loadu(&inputs[1][block_offset + 0 * sizeof(__m256i)]); + out[2] = loadu(&inputs[2][block_offset + 0 * sizeof(__m256i)]); + out[3] = loadu(&inputs[3][block_offset + 0 * sizeof(__m256i)]); + out[4] = loadu(&inputs[4][block_offset + 0 * sizeof(__m256i)]); + out[5] = loadu(&inputs[5][block_offset + 0 * sizeof(__m256i)]); + out[6] = loadu(&inputs[6][block_offset + 0 * sizeof(__m256i)]); + out[7] = loadu(&inputs[7][block_offset + 0 * sizeof(__m256i)]); + out[8] = loadu(&inputs[0][block_offset + 1 * sizeof(__m256i)]); + out[9] = loadu(&inputs[1][block_offset + 1 * sizeof(__m256i)]); + out[10] = loadu(&inputs[2][block_offset + 1 * sizeof(__m256i)]); + out[11] = loadu(&inputs[3][block_offset + 1 * sizeof(__m256i)]); + out[12] = loadu(&inputs[4][block_offset + 1 * sizeof(__m256i)]); + out[13] = loadu(&inputs[5][block_offset + 1 * sizeof(__m256i)]); + out[14] = loadu(&inputs[6][block_offset + 1 * sizeof(__m256i)]); + out[15] = loadu(&inputs[7][block_offset + 1 * sizeof(__m256i)]); + for (size_t i = 0; i < 8; ++i) { + _mm_prefetch(&inputs[i][block_offset + 256], _MM_HINT_T0); + } + transpose_vecs(&out[0]); + transpose_vecs(&out[8]); +} + +INLINE void load_counters(uint64_t counter, bool increment_counter, + __m256i *out_lo, __m256i *out_hi) { + const __m256i mask = _mm256_set1_epi32(-(int32_t)increment_counter); + const __m256i add0 = _mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0); + const __m256i add1 = _mm256_and_si256(mask, add0); + __m256i l = _mm256_add_epi32(_mm256_set1_epi32(counter), add1); + __m256i carry = _mm256_cmpgt_epi32(_mm256_xor_si256(add1, _mm256_set1_epi32(0x80000000)), + _mm256_xor_si256( l, _mm256_set1_epi32(0x80000000))); + __m256i h = _mm256_sub_epi32(_mm256_set1_epi32(counter >> 32), carry); + *out_lo = l; + *out_hi = h; +} + +void blake3_hash8_avx2(const uint8_t *const *inputs, size_t blocks, + const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, uint8_t *out) { + __m256i h_vecs[8] = { + set1(key[0]), set1(key[1]), set1(key[2]), set1(key[3]), + set1(key[4]), set1(key[5]), set1(key[6]), set1(key[7]), + }; + __m256i counter_low_vec, counter_high_vec; + load_counters(counter, increment_counter, &counter_low_vec, + &counter_high_vec); + uint8_t block_flags = flags | flags_start; + + for (size_t block = 0; block < blocks; block++) { + if (block + 1 == blocks) { + block_flags |= flags_end; + } + __m256i block_len_vec = set1(BLAKE3_BLOCK_LEN); + __m256i block_flags_vec = set1(block_flags); + __m256i msg_vecs[16]; + transpose_msg_vecs(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); + + __m256i v[16] = { + h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], + h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], + set1(IV[0]), set1(IV[1]), set1(IV[2]), set1(IV[3]), + counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, + }; + round_fn(v, msg_vecs, 0); + round_fn(v, msg_vecs, 1); + round_fn(v, msg_vecs, 2); + round_fn(v, msg_vecs, 3); + round_fn(v, msg_vecs, 4); + round_fn(v, msg_vecs, 5); + round_fn(v, msg_vecs, 6); + h_vecs[0] = xorv(v[0], v[8]); + h_vecs[1] = xorv(v[1], v[9]); + h_vecs[2] = xorv(v[2], v[10]); + h_vecs[3] = xorv(v[3], v[11]); + h_vecs[4] = xorv(v[4], v[12]); + h_vecs[5] = xorv(v[5], v[13]); + h_vecs[6] = xorv(v[6], v[14]); + h_vecs[7] = xorv(v[7], v[15]); + + block_flags = flags; + } + + transpose_vecs(h_vecs); + storeu(h_vecs[0], &out[0 * sizeof(__m256i)]); + storeu(h_vecs[1], &out[1 * sizeof(__m256i)]); + storeu(h_vecs[2], &out[2 * sizeof(__m256i)]); + storeu(h_vecs[3], &out[3 * sizeof(__m256i)]); + storeu(h_vecs[4], &out[4 * sizeof(__m256i)]); + storeu(h_vecs[5], &out[5 * sizeof(__m256i)]); + storeu(h_vecs[6], &out[6 * sizeof(__m256i)]); + storeu(h_vecs[7], &out[7 * sizeof(__m256i)]); +} + +#if !defined(BLAKE3_NO_SSE41) +void blake3_hash_many_sse41(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out); +#else +void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out); +#endif + +void blake3_hash_many_avx2(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out) { + while (num_inputs >= DEGREE) { + blake3_hash8_avx2(inputs, blocks, key, counter, increment_counter, flags, + flags_start, flags_end, out); + if (increment_counter) { + counter += DEGREE; + } + inputs += DEGREE; + num_inputs -= DEGREE; + out = &out[DEGREE * BLAKE3_OUT_LEN]; + } +#if !defined(BLAKE3_NO_SSE41) + blake3_hash_many_sse41(inputs, num_inputs, blocks, key, counter, + increment_counter, flags, flags_start, flags_end, out); +#else + blake3_hash_many_portable(inputs, num_inputs, blocks, key, counter, + increment_counter, flags, flags_start, flags_end, + out); +#endif +} diff --git a/src/Native/libmultihash/blake3/blake3_avx2_x86-64_unix.S b/src/Native/libmultihash/blake3/blake3_avx2_x86-64_unix.S new file mode 100644 index 000000000..14dcf5b46 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx2_x86-64_unix.S @@ -0,0 +1,1811 @@ +#if defined(__ELF__) && defined(__CET__) && defined(__has_include) +#if __has_include() +#include +#endif +#endif + +#if !defined(_CET_ENDBR) +#define _CET_ENDBR +#endif + +.intel_syntax noprefix +.global _blake3_hash_many_avx2 +.global blake3_hash_many_avx2 +#ifdef __APPLE__ +.text +#else +.section .text +#endif + .p2align 6 +_blake3_hash_many_avx2: +blake3_hash_many_avx2: + _CET_ENDBR + push r15 + push r14 + push r13 + push r12 + push rbx + push rbp + mov rbp, rsp + sub rsp, 680 + and rsp, 0xFFFFFFFFFFFFFFC0 + neg r9d + vmovd xmm0, r9d + vpbroadcastd ymm0, xmm0 + vmovdqa ymmword ptr [rsp+0x280], ymm0 + vpand ymm1, ymm0, ymmword ptr [ADD0+rip] + vpand ymm2, ymm0, ymmword ptr [ADD1+rip] + vmovdqa ymmword ptr [rsp+0x220], ymm2 + vmovd xmm2, r8d + vpbroadcastd ymm2, xmm2 + vpaddd ymm2, ymm2, ymm1 + vmovdqa ymmword ptr [rsp+0x240], ymm2 + vpxor ymm1, ymm1, ymmword ptr [CMP_MSB_MASK+rip] + vpxor ymm2, ymm2, ymmword ptr [CMP_MSB_MASK+rip] + vpcmpgtd ymm2, ymm1, ymm2 + shr r8, 32 + vmovd xmm3, r8d + vpbroadcastd ymm3, xmm3 + vpsubd ymm3, ymm3, ymm2 + vmovdqa ymmword ptr [rsp+0x260], ymm3 + shl rdx, 6 + mov qword ptr [rsp+0x2A0], rdx + cmp rsi, 8 + jc 3f +2: + vpbroadcastd ymm0, dword ptr [rcx] + vpbroadcastd ymm1, dword ptr [rcx+0x4] + vpbroadcastd ymm2, dword ptr [rcx+0x8] + vpbroadcastd ymm3, dword ptr [rcx+0xC] + vpbroadcastd ymm4, dword ptr [rcx+0x10] + vpbroadcastd ymm5, dword ptr [rcx+0x14] + vpbroadcastd ymm6, dword ptr [rcx+0x18] + vpbroadcastd ymm7, dword ptr [rcx+0x1C] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x20] + mov r13, qword ptr [rdi+0x28] + mov r14, qword ptr [rdi+0x30] + mov r15, qword ptr [rdi+0x38] + movzx eax, byte ptr [rbp+0x38] + movzx ebx, byte ptr [rbp+0x40] + or eax, ebx + xor edx, edx +.p2align 5 +9: + movzx ebx, byte ptr [rbp+0x48] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+0x2A0] + cmove eax, ebx + mov dword ptr [rsp+0x200], eax + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x40] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x40] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x40] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0x20], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0x40], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0x60], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-0x30] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x30] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x30] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+0x80], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0xA0], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0xC0], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0xE0], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x20] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x20] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x20] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+0x100], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0x120], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0x140], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0x160], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-0x10] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x10] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x10] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+0x180], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0x1A0], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0x1C0], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0x1E0], ymm11 + vpbroadcastd ymm15, dword ptr [rsp+0x200] + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r12+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r13+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r14+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + prefetcht0 [r15+rdx+0x80] + vpaddd ymm0, ymm0, ymmword ptr [rsp] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm0, ymmword ptr [rsp+0x240] + vpxor ymm13, ymm1, ymmword ptr [rsp+0x260] + vpxor ymm14, ymm2, ymmword ptr [BLAKE3_BLOCK_LEN+rip] + vpxor ymm15, ymm3, ymm15 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [BLAKE3_IV_0+rip] + vpaddd ymm9, ymm13, ymmword ptr [BLAKE3_IV_1+rip] + vpaddd ymm10, ymm14, ymmword ptr [BLAKE3_IV_2+rip] + vpaddd ymm11, ymm15, ymmword ptr [BLAKE3_IV_3+rip] + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x100] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xE0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x160] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xA0] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x180] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x140] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xC0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1E0] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vpxor ymm0, ymm0, ymm8 + vpxor ymm1, ymm1, ymm9 + vpxor ymm2, ymm2, ymm10 + vpxor ymm3, ymm3, ymm11 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpxor ymm4, ymm4, ymm12 + vpxor ymm5, ymm5, ymm13 + vpxor ymm6, ymm6, ymm14 + vpxor ymm7, ymm7, ymm15 + movzx eax, byte ptr [rbp+0x38] + jne 9b + mov rbx, qword ptr [rbp+0x50] + vunpcklps ymm8, ymm0, ymm1 + vunpcklps ymm9, ymm2, ymm3 + vunpckhps ymm10, ymm0, ymm1 + vunpcklps ymm11, ymm4, ymm5 + vunpcklps ymm0, ymm6, ymm7 + vshufps ymm12, ymm8, ymm9, 78 + vblendps ymm1, ymm8, ymm12, 0xCC + vshufps ymm8, ymm11, ymm0, 78 + vunpckhps ymm13, ymm2, ymm3 + vblendps ymm2, ymm11, ymm8, 0xCC + vblendps ymm3, ymm12, ymm9, 0xCC + vperm2f128 ymm12, ymm1, ymm2, 0x20 + vmovups ymmword ptr [rbx], ymm12 + vunpckhps ymm14, ymm4, ymm5 + vblendps ymm4, ymm8, ymm0, 0xCC + vunpckhps ymm15, ymm6, ymm7 + vperm2f128 ymm7, ymm3, ymm4, 0x20 + vmovups ymmword ptr [rbx+0x20], ymm7 + vshufps ymm5, ymm10, ymm13, 78 + vblendps ymm6, ymm5, ymm13, 0xCC + vshufps ymm13, ymm14, ymm15, 78 + vblendps ymm10, ymm10, ymm5, 0xCC + vblendps ymm14, ymm14, ymm13, 0xCC + vperm2f128 ymm8, ymm10, ymm14, 0x20 + vmovups ymmword ptr [rbx+0x40], ymm8 + vblendps ymm15, ymm13, ymm15, 0xCC + vperm2f128 ymm13, ymm6, ymm15, 0x20 + vmovups ymmword ptr [rbx+0x60], ymm13 + vperm2f128 ymm9, ymm1, ymm2, 0x31 + vperm2f128 ymm11, ymm3, ymm4, 0x31 + vmovups ymmword ptr [rbx+0x80], ymm9 + vperm2f128 ymm14, ymm10, ymm14, 0x31 + vperm2f128 ymm15, ymm6, ymm15, 0x31 + vmovups ymmword ptr [rbx+0xA0], ymm11 + vmovups ymmword ptr [rbx+0xC0], ymm14 + vmovups ymmword ptr [rbx+0xE0], ymm15 + vmovdqa ymm0, ymmword ptr [rsp+0x220] + vpaddd ymm1, ymm0, ymmword ptr [rsp+0x240] + vmovdqa ymmword ptr [rsp+0x240], ymm1 + vpxor ymm0, ymm0, ymmword ptr [CMP_MSB_MASK+rip] + vpxor ymm2, ymm1, ymmword ptr [CMP_MSB_MASK+rip] + vpcmpgtd ymm2, ymm0, ymm2 + vmovdqa ymm0, ymmword ptr [rsp+0x260] + vpsubd ymm2, ymm0, ymm2 + vmovdqa ymmword ptr [rsp+0x260], ymm2 + add rdi, 64 + add rbx, 256 + mov qword ptr [rbp+0x50], rbx + sub rsi, 8 + cmp rsi, 8 + jnc 2b + test rsi, rsi + jnz 3f +4: + vzeroupper + mov rsp, rbp + pop rbp + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + ret +.p2align 5 +3: + mov rbx, qword ptr [rbp+0x50] + mov r15, qword ptr [rsp+0x2A0] + movzx r13d, byte ptr [rbp+0x38] + movzx r12d, byte ptr [rbp+0x48] + test rsi, 0x4 + je 3f + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] + vmovdqa ymm8, ymm0 + vmovdqa ymm9, ymm1 + vbroadcasti128 ymm12, xmmword ptr [rsp+0x240] + vbroadcasti128 ymm13, xmmword ptr [rsp+0x260] + vpunpckldq ymm14, ymm12, ymm13 + vpunpckhdq ymm15, ymm12, ymm13 + vpermq ymm14, ymm14, 0x50 + vpermq ymm15, ymm15, 0x50 + vbroadcasti128 ymm12, xmmword ptr [BLAKE3_BLOCK_LEN+rip] + vpblendd ymm14, ymm14, ymm12, 0x44 + vpblendd ymm15, ymm15, ymm12, 0x44 + vmovdqa ymmword ptr [rsp], ymm14 + vmovdqa ymmword ptr [rsp+0x20], ymm15 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x200], eax + vmovups ymm2, ymmword ptr [r8+rdx-0x40] + vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x40], 0x01 + vmovups ymm3, ymmword ptr [r8+rdx-0x30] + vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x30], 0x01 + vshufps ymm4, ymm2, ymm3, 136 + vshufps ymm5, ymm2, ymm3, 221 + vmovups ymm2, ymmword ptr [r8+rdx-0x20] + vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x20], 0x01 + vmovups ymm3, ymmword ptr [r8+rdx-0x10] + vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x10], 0x01 + vshufps ymm6, ymm2, ymm3, 136 + vshufps ymm7, ymm2, ymm3, 221 + vpshufd ymm6, ymm6, 0x93 + vpshufd ymm7, ymm7, 0x93 + vmovups ymm10, ymmword ptr [r10+rdx-0x40] + vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x40], 0x01 + vmovups ymm11, ymmword ptr [r10+rdx-0x30] + vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x30], 0x01 + vshufps ymm12, ymm10, ymm11, 136 + vshufps ymm13, ymm10, ymm11, 221 + vmovups ymm10, ymmword ptr [r10+rdx-0x20] + vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x20], 0x01 + vmovups ymm11, ymmword ptr [r10+rdx-0x10] + vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x10], 0x01 + vshufps ymm14, ymm10, ymm11, 136 + vshufps ymm15, ymm10, ymm11, 221 + vpshufd ymm14, ymm14, 0x93 + vpshufd ymm15, ymm15, 0x93 + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + vpbroadcastd ymm2, dword ptr [rsp+0x200] + vmovdqa ymm3, ymmword ptr [rsp] + vmovdqa ymm11, ymmword ptr [rsp+0x20] + vpblendd ymm3, ymm3, ymm2, 0x88 + vpblendd ymm11, ymm11, ymm2, 0x88 + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] + vmovdqa ymm10, ymm2 + mov al, 7 +9: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm8, ymm8, ymm12 + vmovdqa ymmword ptr [rsp+0x40], ymm4 + nop + vmovdqa ymmword ptr [rsp+0x60], ymm12 + nop + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 12 + vpslld ymm9, ymm9, 20 + vpor ymm9, ymm9, ymm4 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vmovdqa ymmword ptr [rsp+0x80], ymm5 + vmovdqa ymmword ptr [rsp+0xA0], ymm13 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 7 + vpslld ymm9, ymm9, 25 + vpor ymm9, ymm9, ymm4 + vpshufd ymm0, ymm0, 0x93 + vpshufd ymm8, ymm8, 0x93 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm11, ymm11, 0x4E + vpshufd ymm2, ymm2, 0x39 + vpshufd ymm10, ymm10, 0x39 + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm8, ymm8, ymm14 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 12 + vpslld ymm9, ymm9, 20 + vpor ymm9, ymm9, ymm4 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm8, ymm8, ymm15 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 7 + vpslld ymm9, ymm9, 25 + vpor ymm9, ymm9, ymm4 + vpshufd ymm0, ymm0, 0x39 + vpshufd ymm8, ymm8, 0x39 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm11, ymm11, 0x4E + vpshufd ymm2, ymm2, 0x93 + vpshufd ymm10, ymm10, 0x93 + dec al + je 9f + vmovdqa ymm4, ymmword ptr [rsp+0x40] + vmovdqa ymm5, ymmword ptr [rsp+0x80] + vshufps ymm12, ymm4, ymm5, 214 + vpshufd ymm13, ymm4, 0x0F + vpshufd ymm4, ymm12, 0x39 + vshufps ymm12, ymm6, ymm7, 250 + vpblendd ymm13, ymm13, ymm12, 0xAA + vpunpcklqdq ymm12, ymm7, ymm5 + vpblendd ymm12, ymm12, ymm6, 0x88 + vpshufd ymm12, ymm12, 0x78 + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 0x1E + vmovdqa ymmword ptr [rsp+0x40], ymm13 + vmovdqa ymmword ptr [rsp+0x80], ymm12 + vmovdqa ymm12, ymmword ptr [rsp+0x60] + vmovdqa ymm13, ymmword ptr [rsp+0xA0] + vshufps ymm5, ymm12, ymm13, 214 + vpshufd ymm6, ymm12, 0x0F + vpshufd ymm12, ymm5, 0x39 + vshufps ymm5, ymm14, ymm15, 250 + vpblendd ymm6, ymm6, ymm5, 0xAA + vpunpcklqdq ymm5, ymm15, ymm13 + vpblendd ymm5, ymm5, ymm14, 0x88 + vpshufd ymm5, ymm5, 0x78 + vpunpckhdq ymm13, ymm13, ymm15 + vpunpckldq ymm14, ymm14, ymm13 + vpshufd ymm15, ymm14, 0x1E + vmovdqa ymm13, ymm6 + vmovdqa ymm14, ymm5 + vmovdqa ymm5, ymmword ptr [rsp+0x40] + vmovdqa ymm6, ymmword ptr [rsp+0x80] + jmp 9b +9: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + vpxor ymm8, ymm8, ymm10 + vpxor ymm9, ymm9, ymm11 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vmovdqu xmmword ptr [rbx+0x40], xmm8 + vmovdqu xmmword ptr [rbx+0x50], xmm9 + vextracti128 xmmword ptr [rbx+0x60], ymm8, 0x01 + vextracti128 xmmword ptr [rbx+0x70], ymm9, 0x01 + vmovaps xmm8, xmmword ptr [rsp+0x280] + vmovaps xmm0, xmmword ptr [rsp+0x240] + vmovaps xmm1, xmmword ptr [rsp+0x250] + vmovaps xmm2, xmmword ptr [rsp+0x260] + vmovaps xmm3, xmmword ptr [rsp+0x270] + vblendvps xmm0, xmm0, xmm1, xmm8 + vblendvps xmm2, xmm2, xmm3, xmm8 + vmovaps xmmword ptr [rsp+0x240], xmm0 + vmovaps xmmword ptr [rsp+0x260], xmm2 + add rbx, 128 + add rdi, 32 + sub rsi, 4 +3: + test rsi, 0x2 + je 3f + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] + vmovd xmm13, dword ptr [rsp+0x240] + vpinsrd xmm13, xmm13, dword ptr [rsp+0x260], 1 + vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovd xmm14, dword ptr [rsp+0x244] + vpinsrd xmm14, xmm14, dword ptr [rsp+0x264], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vinserti128 ymm13, ymm13, xmm14, 0x01 + vbroadcasti128 ymm14, xmmword ptr [ROT16+rip] + vbroadcasti128 ymm15, xmmword ptr [ROT8+rip] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x200], eax + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] + vpbroadcastd ymm8, dword ptr [rsp+0x200] + vpblendd ymm3, ymm13, ymm8, 0x88 + vmovups ymm8, ymmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 + vshufps ymm4, ymm8, ymm9, 136 + vshufps ymm5, ymm8, ymm9, 221 + vmovups ymm8, ymmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 + vshufps ymm6, ymm8, ymm9, 136 + vshufps ymm7, ymm8, ymm9, 221 + vpshufd ymm6, ymm6, 0x93 + vpshufd ymm7, ymm7, 0x93 + mov al, 7 +9: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm14 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm8 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm15 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm8 + vpshufd ymm0, ymm0, 0x93 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x39 + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm14 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm8 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm15 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm8 + vpshufd ymm0, ymm0, 0x39 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x93 + dec al + jz 9f + vshufps ymm8, ymm4, ymm5, 214 + vpshufd ymm9, ymm4, 0x0F + vpshufd ymm4, ymm8, 0x39 + vshufps ymm8, ymm6, ymm7, 250 + vpblendd ymm9, ymm9, ymm8, 0xAA + vpunpcklqdq ymm8, ymm7, ymm5 + vpblendd ymm8, ymm8, ymm6, 0x88 + vpshufd ymm8, ymm8, 0x78 + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 0x1E + vmovdqa ymm5, ymm9 + vmovdqa ymm6, ymm8 + jmp 9b +9: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vmovaps ymm8, ymmword ptr [rsp+0x280] + vmovaps ymm0, ymmword ptr [rsp+0x240] + vmovups ymm1, ymmword ptr [rsp+0x248] + vmovaps ymm2, ymmword ptr [rsp+0x260] + vmovups ymm3, ymmword ptr [rsp+0x268] + vblendvps ymm0, ymm0, ymm1, ymm8 + vblendvps ymm2, ymm2, ymm3, ymm8 + vmovaps ymmword ptr [rsp+0x240], ymm0 + vmovaps ymmword ptr [rsp+0x260], ymm2 + add rbx, 64 + add rdi, 16 + sub rsi, 2 +3: + test rsi, 0x1 + je 4b + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+0x10] + vmovd xmm3, dword ptr [rsp+0x240] + vpinsrd xmm3, xmm3, dword ptr [rsp+0x260], 1 + vpinsrd xmm13, xmm3, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovdqa xmm14, xmmword ptr [ROT16+rip] + vmovdqa xmm15, xmmword ptr [ROT8+rip] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + vmovdqa xmm2, xmmword ptr [BLAKE3_IV+rip] + vmovdqa xmm3, xmm13 + vpinsrd xmm3, xmm3, eax, 3 + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vmovups xmm9, xmmword ptr [r8+rdx-0x30] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vmovups xmm9, xmmword ptr [r8+rdx-0x10] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm14 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 12 + vpslld xmm1, xmm1, 20 + vpor xmm1, xmm1, xmm8 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm15 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 7 + vpslld xmm1, xmm1, 25 + vpor xmm1, xmm1, xmm8 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm14 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 12 + vpslld xmm1, xmm1, 20 + vpor xmm1, xmm1, xmm8 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm15 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 7 + vpslld xmm1, xmm1, 25 + vpor xmm1, xmm1, xmm8 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + jmp 4b + + +#ifdef __APPLE__ +.static_data +#else +.section .rodata +#endif +.p2align 6 +ADD0: + .long 0, 1, 2, 3, 4, 5, 6, 7 +ADD1: + .long 8, 8, 8, 8, 8, 8, 8, 8 +BLAKE3_IV_0: + .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 + .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 +BLAKE3_IV_1: + .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 + .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 +BLAKE3_IV_2: + .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 + .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 +BLAKE3_IV_3: + .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A + .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A +BLAKE3_BLOCK_LEN: + .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 + .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 +ROT16: + .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 +ROT8: + .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 +CMP_MSB_MASK: + .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 + .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 +BLAKE3_IV: + .long 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A + diff --git a/src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_gnu.S b/src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_gnu.S new file mode 100644 index 000000000..bb58d2ae6 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_gnu.S @@ -0,0 +1,1817 @@ +.intel_syntax noprefix +.global _blake3_hash_many_avx2 +.global blake3_hash_many_avx2 +.section .text + .p2align 6 +_blake3_hash_many_avx2: +blake3_hash_many_avx2: + push r15 + push r14 + push r13 + push r12 + push rsi + push rdi + push rbx + push rbp + mov rbp, rsp + sub rsp, 880 + and rsp, 0xFFFFFFFFFFFFFFC0 + vmovdqa xmmword ptr [rsp+0x2D0], xmm6 + vmovdqa xmmword ptr [rsp+0x2E0], xmm7 + vmovdqa xmmword ptr [rsp+0x2F0], xmm8 + vmovdqa xmmword ptr [rsp+0x300], xmm9 + vmovdqa xmmword ptr [rsp+0x310], xmm10 + vmovdqa xmmword ptr [rsp+0x320], xmm11 + vmovdqa xmmword ptr [rsp+0x330], xmm12 + vmovdqa xmmword ptr [rsp+0x340], xmm13 + vmovdqa xmmword ptr [rsp+0x350], xmm14 + vmovdqa xmmword ptr [rsp+0x360], xmm15 + mov rdi, rcx + mov rsi, rdx + mov rdx, r8 + mov rcx, r9 + mov r8, qword ptr [rbp+0x68] + movzx r9, byte ptr [rbp+0x70] + neg r9d + vmovd xmm0, r9d + vpbroadcastd ymm0, xmm0 + vmovdqa ymmword ptr [rsp+0x260], ymm0 + vpand ymm1, ymm0, ymmword ptr [ADD0+rip] + vpand ymm2, ymm0, ymmword ptr [ADD1+rip] + vmovdqa ymmword ptr [rsp+0x2A0], ymm2 + vmovd xmm2, r8d + vpbroadcastd ymm2, xmm2 + vpaddd ymm2, ymm2, ymm1 + vmovdqa ymmword ptr [rsp+0x220], ymm2 + vpxor ymm1, ymm1, ymmword ptr [CMP_MSB_MASK+rip] + vpxor ymm2, ymm2, ymmword ptr [CMP_MSB_MASK+rip] + vpcmpgtd ymm2, ymm1, ymm2 + shr r8, 32 + vmovd xmm3, r8d + vpbroadcastd ymm3, xmm3 + vpsubd ymm3, ymm3, ymm2 + vmovdqa ymmword ptr [rsp+0x240], ymm3 + shl rdx, 6 + mov qword ptr [rsp+0x2C0], rdx + cmp rsi, 8 + jc 3f +2: + vpbroadcastd ymm0, dword ptr [rcx] + vpbroadcastd ymm1, dword ptr [rcx+0x4] + vpbroadcastd ymm2, dword ptr [rcx+0x8] + vpbroadcastd ymm3, dword ptr [rcx+0xC] + vpbroadcastd ymm4, dword ptr [rcx+0x10] + vpbroadcastd ymm5, dword ptr [rcx+0x14] + vpbroadcastd ymm6, dword ptr [rcx+0x18] + vpbroadcastd ymm7, dword ptr [rcx+0x1C] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x20] + mov r13, qword ptr [rdi+0x28] + mov r14, qword ptr [rdi+0x30] + mov r15, qword ptr [rdi+0x38] + movzx eax, byte ptr [rbp+0x78] + movzx ebx, byte ptr [rbp+0x80] + or eax, ebx + xor edx, edx +.p2align 5 +9: + movzx ebx, byte ptr [rbp+0x88] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+0x2C0] + cmove eax, ebx + mov dword ptr [rsp+0x200], eax + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x40] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x40] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x40] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0x20], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0x40], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0x60], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-0x30] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x30] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x30] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+0x80], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0xA0], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0xC0], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0xE0], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x20] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x20] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x20] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+0x100], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0x120], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0x140], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0x160], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-0x10] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x10] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x10] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+0x180], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0x1A0], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0x1C0], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0x1E0], ymm11 + vpbroadcastd ymm15, dword ptr [rsp+0x200] + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r12+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r13+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r14+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + prefetcht0 [r15+rdx+0x80] + vpaddd ymm0, ymm0, ymmword ptr [rsp] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm0, ymmword ptr [rsp+0x220] + vpxor ymm13, ymm1, ymmword ptr [rsp+0x240] + vpxor ymm14, ymm2, ymmword ptr [BLAKE3_BLOCK_LEN+rip] + vpxor ymm15, ymm3, ymm15 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [BLAKE3_IV_0+rip] + vpaddd ymm9, ymm13, ymmword ptr [BLAKE3_IV_1+rip] + vpaddd ymm10, ymm14, ymmword ptr [BLAKE3_IV_2+rip] + vpaddd ymm11, ymm15, ymmword ptr [BLAKE3_IV_3+rip] + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x100] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xE0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x20] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1A0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xC0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x160] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xA0] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1C0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x80] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xA0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x180] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x120] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x1E0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1C0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x140] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0xE0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x40] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x60] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x120] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x160] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x100] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1E0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x180] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x20] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1A0] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x40] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x80] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x60] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x140] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0xC0] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x160] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0xA0] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x20] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x100] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1E0] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x120] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xC0] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x1C0] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x40] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x60] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0xE0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+0x200], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0x140] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0x180] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0x80] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0x1A0] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8+rip] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+0x200] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vpxor ymm0, ymm0, ymm8 + vpxor ymm1, ymm1, ymm9 + vpxor ymm2, ymm2, ymm10 + vpxor ymm3, ymm3, ymm11 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpxor ymm4, ymm4, ymm12 + vpxor ymm5, ymm5, ymm13 + vpxor ymm6, ymm6, ymm14 + vpxor ymm7, ymm7, ymm15 + movzx eax, byte ptr [rbp+0x78] + jne 9b + mov rbx, qword ptr [rbp+0x90] + vunpcklps ymm8, ymm0, ymm1 + vunpcklps ymm9, ymm2, ymm3 + vunpckhps ymm10, ymm0, ymm1 + vunpcklps ymm11, ymm4, ymm5 + vunpcklps ymm0, ymm6, ymm7 + vshufps ymm12, ymm8, ymm9, 78 + vblendps ymm1, ymm8, ymm12, 0xCC + vshufps ymm8, ymm11, ymm0, 78 + vunpckhps ymm13, ymm2, ymm3 + vblendps ymm2, ymm11, ymm8, 0xCC + vblendps ymm3, ymm12, ymm9, 0xCC + vperm2f128 ymm12, ymm1, ymm2, 0x20 + vmovups ymmword ptr [rbx], ymm12 + vunpckhps ymm14, ymm4, ymm5 + vblendps ymm4, ymm8, ymm0, 0xCC + vunpckhps ymm15, ymm6, ymm7 + vperm2f128 ymm7, ymm3, ymm4, 0x20 + vmovups ymmword ptr [rbx+0x20], ymm7 + vshufps ymm5, ymm10, ymm13, 78 + vblendps ymm6, ymm5, ymm13, 0xCC + vshufps ymm13, ymm14, ymm15, 78 + vblendps ymm10, ymm10, ymm5, 0xCC + vblendps ymm14, ymm14, ymm13, 0xCC + vperm2f128 ymm8, ymm10, ymm14, 0x20 + vmovups ymmword ptr [rbx+0x40], ymm8 + vblendps ymm15, ymm13, ymm15, 0xCC + vperm2f128 ymm13, ymm6, ymm15, 0x20 + vmovups ymmword ptr [rbx+0x60], ymm13 + vperm2f128 ymm9, ymm1, ymm2, 0x31 + vperm2f128 ymm11, ymm3, ymm4, 0x31 + vmovups ymmword ptr [rbx+0x80], ymm9 + vperm2f128 ymm14, ymm10, ymm14, 0x31 + vperm2f128 ymm15, ymm6, ymm15, 0x31 + vmovups ymmword ptr [rbx+0xA0], ymm11 + vmovups ymmword ptr [rbx+0xC0], ymm14 + vmovups ymmword ptr [rbx+0xE0], ymm15 + vmovdqa ymm0, ymmword ptr [rsp+0x2A0] + vpaddd ymm1, ymm0, ymmword ptr [rsp+0x220] + vmovdqa ymmword ptr [rsp+0x220], ymm1 + vpxor ymm0, ymm0, ymmword ptr [CMP_MSB_MASK+rip] + vpxor ymm2, ymm1, ymmword ptr [CMP_MSB_MASK+rip] + vpcmpgtd ymm2, ymm0, ymm2 + vmovdqa ymm0, ymmword ptr [rsp+0x240] + vpsubd ymm2, ymm0, ymm2 + vmovdqa ymmword ptr [rsp+0x240], ymm2 + add rdi, 64 + add rbx, 256 + mov qword ptr [rbp+0x90], rbx + sub rsi, 8 + cmp rsi, 8 + jnc 2b + test rsi, rsi + jnz 3f +4: + vzeroupper + vmovdqa xmm6, xmmword ptr [rsp+0x2D0] + vmovdqa xmm7, xmmword ptr [rsp+0x2E0] + vmovdqa xmm8, xmmword ptr [rsp+0x2F0] + vmovdqa xmm9, xmmword ptr [rsp+0x300] + vmovdqa xmm10, xmmword ptr [rsp+0x310] + vmovdqa xmm11, xmmword ptr [rsp+0x320] + vmovdqa xmm12, xmmword ptr [rsp+0x330] + vmovdqa xmm13, xmmword ptr [rsp+0x340] + vmovdqa xmm14, xmmword ptr [rsp+0x350] + vmovdqa xmm15, xmmword ptr [rsp+0x360] + mov rsp, rbp + pop rbp + pop rbx + pop rdi + pop rsi + pop r12 + pop r13 + pop r14 + pop r15 + ret +.p2align 5 +3: + mov rbx, qword ptr [rbp+0x90] + mov r15, qword ptr [rsp+0x2C0] + movzx r13d, byte ptr [rbp+0x78] + movzx r12d, byte ptr [rbp+0x88] + test rsi, 0x4 + je 3f + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] + vmovdqa ymm8, ymm0 + vmovdqa ymm9, ymm1 + vbroadcasti128 ymm12, xmmword ptr [rsp+0x220] + vbroadcasti128 ymm13, xmmword ptr [rsp+0x240] + vpunpckldq ymm14, ymm12, ymm13 + vpunpckhdq ymm15, ymm12, ymm13 + vpermq ymm14, ymm14, 0x50 + vpermq ymm15, ymm15, 0x50 + vbroadcasti128 ymm12, xmmword ptr [BLAKE3_BLOCK_LEN+rip] + vpblendd ymm14, ymm14, ymm12, 0x44 + vpblendd ymm15, ymm15, ymm12, 0x44 + vmovdqa ymmword ptr [rsp], ymm14 + vmovdqa ymmword ptr [rsp+0x20], ymm15 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x200], eax + vmovups ymm2, ymmword ptr [r8+rdx-0x40] + vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x40], 0x01 + vmovups ymm3, ymmword ptr [r8+rdx-0x30] + vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x30], 0x01 + vshufps ymm4, ymm2, ymm3, 136 + vshufps ymm5, ymm2, ymm3, 221 + vmovups ymm2, ymmword ptr [r8+rdx-0x20] + vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-0x20], 0x01 + vmovups ymm3, ymmword ptr [r8+rdx-0x10] + vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-0x10], 0x01 + vshufps ymm6, ymm2, ymm3, 136 + vshufps ymm7, ymm2, ymm3, 221 + vpshufd ymm6, ymm6, 0x93 + vpshufd ymm7, ymm7, 0x93 + vmovups ymm10, ymmword ptr [r10+rdx-0x40] + vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x40], 0x01 + vmovups ymm11, ymmword ptr [r10+rdx-0x30] + vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x30], 0x01 + vshufps ymm12, ymm10, ymm11, 136 + vshufps ymm13, ymm10, ymm11, 221 + vmovups ymm10, ymmword ptr [r10+rdx-0x20] + vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-0x20], 0x01 + vmovups ymm11, ymmword ptr [r10+rdx-0x10] + vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-0x10], 0x01 + vshufps ymm14, ymm10, ymm11, 136 + vshufps ymm15, ymm10, ymm11, 221 + vpshufd ymm14, ymm14, 0x93 + vpshufd ymm15, ymm15, 0x93 + vpbroadcastd ymm2, dword ptr [rsp+0x200] + vmovdqa ymm3, ymmword ptr [rsp] + vmovdqa ymm11, ymmword ptr [rsp+0x20] + vpblendd ymm3, ymm3, ymm2, 0x88 + vpblendd ymm11, ymm11, ymm2, 0x88 + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] + vmovdqa ymm10, ymm2 + mov al, 7 +9: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm8, ymm8, ymm12 + vmovdqa ymmword ptr [rsp+0x40], ymm4 + nop + vmovdqa ymmword ptr [rsp+0x60], ymm12 + nop + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 12 + vpslld ymm9, ymm9, 20 + vpor ymm9, ymm9, ymm4 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vmovdqa ymmword ptr [rsp+0x80], ymm5 + vmovdqa ymmword ptr [rsp+0xA0], ymm13 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 7 + vpslld ymm9, ymm9, 25 + vpor ymm9, ymm9, ymm4 + vpshufd ymm0, ymm0, 0x93 + vpshufd ymm8, ymm8, 0x93 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm11, ymm11, 0x4E + vpshufd ymm2, ymm2, 0x39 + vpshufd ymm10, ymm10, 0x39 + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm8, ymm8, ymm14 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT16+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 12 + vpslld ymm9, ymm9, 20 + vpor ymm9, ymm9, ymm4 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm8, ymm8, ymm15 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT8+rip] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 7 + vpslld ymm9, ymm9, 25 + vpor ymm9, ymm9, ymm4 + vpshufd ymm0, ymm0, 0x39 + vpshufd ymm8, ymm8, 0x39 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm11, ymm11, 0x4E + vpshufd ymm2, ymm2, 0x93 + vpshufd ymm10, ymm10, 0x93 + dec al + je 9f + vmovdqa ymm4, ymmword ptr [rsp+0x40] + vmovdqa ymm5, ymmword ptr [rsp+0x80] + vshufps ymm12, ymm4, ymm5, 214 + vpshufd ymm13, ymm4, 0x0F + vpshufd ymm4, ymm12, 0x39 + vshufps ymm12, ymm6, ymm7, 250 + vpblendd ymm13, ymm13, ymm12, 0xAA + vpunpcklqdq ymm12, ymm7, ymm5 + vpblendd ymm12, ymm12, ymm6, 0x88 + vpshufd ymm12, ymm12, 0x78 + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 0x1E + vmovdqa ymmword ptr [rsp+0x40], ymm13 + vmovdqa ymmword ptr [rsp+0x80], ymm12 + vmovdqa ymm12, ymmword ptr [rsp+0x60] + vmovdqa ymm13, ymmword ptr [rsp+0xA0] + vshufps ymm5, ymm12, ymm13, 214 + vpshufd ymm6, ymm12, 0x0F + vpshufd ymm12, ymm5, 0x39 + vshufps ymm5, ymm14, ymm15, 250 + vpblendd ymm6, ymm6, ymm5, 0xAA + vpunpcklqdq ymm5, ymm15, ymm13 + vpblendd ymm5, ymm5, ymm14, 0x88 + vpshufd ymm5, ymm5, 0x78 + vpunpckhdq ymm13, ymm13, ymm15 + vpunpckldq ymm14, ymm14, ymm13 + vpshufd ymm15, ymm14, 0x1E + vmovdqa ymm13, ymm6 + vmovdqa ymm14, ymm5 + vmovdqa ymm5, ymmword ptr [rsp+0x40] + vmovdqa ymm6, ymmword ptr [rsp+0x80] + jmp 9b +9: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + vpxor ymm8, ymm8, ymm10 + vpxor ymm9, ymm9, ymm11 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vmovdqu xmmword ptr [rbx+0x40], xmm8 + vmovdqu xmmword ptr [rbx+0x50], xmm9 + vextracti128 xmmword ptr [rbx+0x60], ymm8, 0x01 + vextracti128 xmmword ptr [rbx+0x70], ymm9, 0x01 + vmovaps xmm8, xmmword ptr [rsp+0x260] + vmovaps xmm0, xmmword ptr [rsp+0x220] + vmovaps xmm1, xmmword ptr [rsp+0x230] + vmovaps xmm2, xmmword ptr [rsp+0x240] + vmovaps xmm3, xmmword ptr [rsp+0x250] + vblendvps xmm0, xmm0, xmm1, xmm8 + vblendvps xmm2, xmm2, xmm3, xmm8 + vmovaps xmmword ptr [rsp+0x220], xmm0 + vmovaps xmmword ptr [rsp+0x240], xmm2 + add rbx, 128 + add rdi, 32 + sub rsi, 4 +3: + test rsi, 0x2 + je 3f + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] + vmovd xmm13, dword ptr [rsp+0x220] + vpinsrd xmm13, xmm13, dword ptr [rsp+0x240], 1 + vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovd xmm14, dword ptr [rsp+0x224] + vpinsrd xmm14, xmm14, dword ptr [rsp+0x244], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vinserti128 ymm13, ymm13, xmm14, 0x01 + vbroadcasti128 ymm14, xmmword ptr [ROT16+rip] + vbroadcasti128 ymm15, xmmword ptr [ROT8+rip] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x200], eax + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] + vpbroadcastd ymm8, dword ptr [rsp+0x200] + vpblendd ymm3, ymm13, ymm8, 0x88 + vmovups ymm8, ymmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 + vshufps ymm4, ymm8, ymm9, 136 + vshufps ymm5, ymm8, ymm9, 221 + vmovups ymm8, ymmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 + vshufps ymm6, ymm8, ymm9, 136 + vshufps ymm7, ymm8, ymm9, 221 + vpshufd ymm6, ymm6, 0x93 + vpshufd ymm7, ymm7, 0x93 + mov al, 7 +9: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm14 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm8 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm15 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm8 + vpshufd ymm0, ymm0, 0x93 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x39 + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm14 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm8 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm15 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm8 + vpshufd ymm0, ymm0, 0x39 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x93 + dec al + jz 9f + vshufps ymm8, ymm4, ymm5, 214 + vpshufd ymm9, ymm4, 0x0F + vpshufd ymm4, ymm8, 0x39 + vshufps ymm8, ymm6, ymm7, 250 + vpblendd ymm9, ymm9, ymm8, 0xAA + vpunpcklqdq ymm8, ymm7, ymm5 + vpblendd ymm8, ymm8, ymm6, 0x88 + vpshufd ymm8, ymm8, 0x78 + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 0x1E + vmovdqa ymm5, ymm9 + vmovdqa ymm6, ymm8 + jmp 9b +9: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vmovaps ymm8, ymmword ptr [rsp+0x260] + vmovaps ymm0, ymmword ptr [rsp+0x220] + vmovups ymm1, ymmword ptr [rsp+0x228] + vmovaps ymm2, ymmword ptr [rsp+0x240] + vmovups ymm3, ymmword ptr [rsp+0x248] + vblendvps ymm0, ymm0, ymm1, ymm8 + vblendvps ymm2, ymm2, ymm3, ymm8 + vmovaps ymmword ptr [rsp+0x220], ymm0 + vmovaps ymmword ptr [rsp+0x240], ymm2 + add rbx, 64 + add rdi, 16 + sub rsi, 2 +3: + test rsi, 0x1 + je 4b + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+0x10] + vmovd xmm3, dword ptr [rsp+0x220] + vpinsrd xmm3, xmm3, dword ptr [rsp+0x240], 1 + vpinsrd xmm13, xmm3, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovdqa xmm14, xmmword ptr [ROT16+rip] + vmovdqa xmm15, xmmword ptr [ROT8+rip] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + vmovdqa xmm2, xmmword ptr [BLAKE3_IV+rip] + vmovdqa xmm3, xmm13 + vpinsrd xmm3, xmm3, eax, 3 + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vmovups xmm9, xmmword ptr [r8+rdx-0x30] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vmovups xmm9, xmmword ptr [r8+rdx-0x10] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm14 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 12 + vpslld xmm1, xmm1, 20 + vpor xmm1, xmm1, xmm8 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm15 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 7 + vpslld xmm1, xmm1, 25 + vpor xmm1, xmm1, xmm8 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm14 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 12 + vpslld xmm1, xmm1, 20 + vpor xmm1, xmm1, xmm8 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm15 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 7 + vpslld xmm1, xmm1, 25 + vpor xmm1, xmm1, xmm8 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + jmp 4b + +.section .rodata +.p2align 6 +ADD0: + .long 0, 1, 2, 3, 4, 5, 6, 7 +ADD1: + .long 8, 8, 8, 8, 8, 8, 8, 8 +BLAKE3_IV_0: + .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 + .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 +BLAKE3_IV_1: + .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 + .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 +BLAKE3_IV_2: + .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 + .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 +BLAKE3_IV_3: + .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A + .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A +BLAKE3_BLOCK_LEN: + .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 + .long 0x00000040, 0x00000040, 0x00000040, 0x00000040 +ROT16: + .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 +ROT8: + .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 +CMP_MSB_MASK: + .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 + .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 +BLAKE3_IV: + .long 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A + diff --git a/src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_msvc.asm b/src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_msvc.asm new file mode 100644 index 000000000..352298edd --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx2_x86-64_windows_msvc.asm @@ -0,0 +1,1828 @@ +public _blake3_hash_many_avx2 +public blake3_hash_many_avx2 + +_TEXT SEGMENT ALIGN(16) 'CODE' + +ALIGN 16 +blake3_hash_many_avx2 PROC +_blake3_hash_many_avx2 PROC + push r15 + push r14 + push r13 + push r12 + push rsi + push rdi + push rbx + push rbp + mov rbp, rsp + sub rsp, 880 + and rsp, 0FFFFFFFFFFFFFFC0H + vmovdqa xmmword ptr [rsp+2D0H], xmm6 + vmovdqa xmmword ptr [rsp+2E0H], xmm7 + vmovdqa xmmword ptr [rsp+2F0H], xmm8 + vmovdqa xmmword ptr [rsp+300H], xmm9 + vmovdqa xmmword ptr [rsp+310H], xmm10 + vmovdqa xmmword ptr [rsp+320H], xmm11 + vmovdqa xmmword ptr [rsp+330H], xmm12 + vmovdqa xmmword ptr [rsp+340H], xmm13 + vmovdqa xmmword ptr [rsp+350H], xmm14 + vmovdqa xmmword ptr [rsp+360H], xmm15 + mov rdi, rcx + mov rsi, rdx + mov rdx, r8 + mov rcx, r9 + mov r8, qword ptr [rbp+68H] + movzx r9, byte ptr [rbp+70H] + neg r9d + vmovd xmm0, r9d + vpbroadcastd ymm0, xmm0 + vmovdqa ymmword ptr [rsp+260H], ymm0 + vpand ymm1, ymm0, ymmword ptr [ADD0] + vpand ymm2, ymm0, ymmword ptr [ADD1] + vmovdqa ymmword ptr [rsp+2A0H], ymm2 + vmovd xmm2, r8d + vpbroadcastd ymm2, xmm2 + vpaddd ymm2, ymm2, ymm1 + vmovdqa ymmword ptr [rsp+220H], ymm2 + vpxor ymm1, ymm1, ymmword ptr [CMP_MSB_MASK] + vpxor ymm2, ymm2, ymmword ptr [CMP_MSB_MASK] + vpcmpgtd ymm2, ymm1, ymm2 + shr r8, 32 + vmovd xmm3, r8d + vpbroadcastd ymm3, xmm3 + vpsubd ymm3, ymm3, ymm2 + vmovdqa ymmword ptr [rsp+240H], ymm3 + shl rdx, 6 + mov qword ptr [rsp+2C0H], rdx + cmp rsi, 8 + jc final7blocks +outerloop8: + vpbroadcastd ymm0, dword ptr [rcx] + vpbroadcastd ymm1, dword ptr [rcx+4H] + vpbroadcastd ymm2, dword ptr [rcx+8H] + vpbroadcastd ymm3, dword ptr [rcx+0CH] + vpbroadcastd ymm4, dword ptr [rcx+10H] + vpbroadcastd ymm5, dword ptr [rcx+14H] + vpbroadcastd ymm6, dword ptr [rcx+18H] + vpbroadcastd ymm7, dword ptr [rcx+1CH] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + mov r10, qword ptr [rdi+10H] + mov r11, qword ptr [rdi+18H] + mov r12, qword ptr [rdi+20H] + mov r13, qword ptr [rdi+28H] + mov r14, qword ptr [rdi+30H] + mov r15, qword ptr [rdi+38H] + movzx eax, byte ptr [rbp+78H] + movzx ebx, byte ptr [rbp+80H] + or eax, ebx + xor edx, edx +ALIGN 16 +innerloop8: + movzx ebx, byte ptr [rbp+88H] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+2C0H] + cmove eax, ebx + mov dword ptr [rsp+200H], eax + vmovups xmm8, xmmword ptr [r8+rdx-40H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-40H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-40H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-40H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-40H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-40H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-40H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-40H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+20H], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+40H], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+60H], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-30H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-30H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-30H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-30H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-30H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-30H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-30H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-30H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+80H], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+0A0H], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+0C0H], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+0E0H], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-20H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-20H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-20H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-20H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-20H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-20H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-20H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-20H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+100H], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+120H], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+140H], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+160H], ymm11 + vmovups xmm8, xmmword ptr [r8+rdx-10H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-10H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-10H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-10H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-10H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-10H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-10H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-10H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm8, ymm12, ymm14, 136 + vmovaps ymmword ptr [rsp+180H], ymm8 + vshufps ymm9, ymm12, ymm14, 221 + vmovaps ymmword ptr [rsp+1A0H], ymm9 + vshufps ymm10, ymm13, ymm15, 136 + vmovaps ymmword ptr [rsp+1C0H], ymm10 + vshufps ymm11, ymm13, ymm15, 221 + vmovaps ymmword ptr [rsp+1E0H], ymm11 + vpbroadcastd ymm15, dword ptr [rsp+200H] + prefetcht0 byte ptr [r8+rdx+80H] + prefetcht0 byte ptr [r12+rdx+80H] + prefetcht0 byte ptr [r9+rdx+80H] + prefetcht0 byte ptr [r13+rdx+80H] + prefetcht0 byte ptr [r10+rdx+80H] + prefetcht0 byte ptr [r14+rdx+80H] + prefetcht0 byte ptr [r11+rdx+80H] + prefetcht0 byte ptr [r15+rdx+80H] + vpaddd ymm0, ymm0, ymmword ptr [rsp] + vpaddd ymm1, ymm1, ymmword ptr [rsp+40H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+80H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm0, ymmword ptr [rsp+220H] + vpxor ymm13, ymm1, ymmword ptr [rsp+240H] + vpxor ymm14, ymm2, ymmword ptr [BLAKE3_BLOCK_LEN] + vpxor ymm15, ymm3, ymm15 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [BLAKE3_IV_0] + vpaddd ymm9, ymm13, ymmword ptr [BLAKE3_IV_1] + vpaddd ymm10, ymm14, ymmword ptr [BLAKE3_IV_2] + vpaddd ymm11, ymm15, ymmword ptr [BLAKE3_IV_3] + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+20H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+60H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0A0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+100H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+180H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1C0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+120H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+1A0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+40H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+60H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0E0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+80H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0C0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] + vpaddd ymm2, ymm2, ymmword ptr [rsp] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1A0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+20H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+120H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+160H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+1C0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+60H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+1A0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+80H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+40H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1C0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0C0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+120H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+160H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0A0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+1E0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+20H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+140H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+1C0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1A0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0E0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+120H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+60H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+80H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0A0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+20H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp] + vpaddd ymm1, ymm1, ymmword ptr [rsp+40H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+100H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+180H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+120H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+1E0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1C0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+1A0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+140H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+0E0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] + vpaddd ymm2, ymm2, ymmword ptr [rsp] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+40H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+60H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+20H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+80H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+120H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+160H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+100H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1E0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+1C0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+180H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+20H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+1A0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+40H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+80H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+60H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+140H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+0C0H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+160H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+0A0H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+20H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+100H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+1E0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp] + vpaddd ymm2, ymm2, ymmword ptr [rsp+120H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0C0H] + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxor ymm12, ymm12, ymm0 + vpxor ymm13, ymm13, ymm1 + vpxor ymm14, ymm14, ymm2 + vpxor ymm15, ymm15, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpshufb ymm15, ymm15, ymm8 + vpaddd ymm8, ymm12, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxor ymm4, ymm4, ymm8 + vpxor ymm5, ymm5, ymm9 + vpxor ymm6, ymm6, ymm10 + vpxor ymm7, ymm7, ymm11 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+1C0H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+40H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+60H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+0E0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT16] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vmovdqa ymmword ptr [rsp+200H], ymm8 + vpsrld ymm8, ymm5, 12 + vpslld ymm5, ymm5, 20 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 12 + vpslld ymm6, ymm6, 20 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 12 + vpslld ymm7, ymm7, 20 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 12 + vpslld ymm4, ymm4, 20 + vpor ymm4, ymm4, ymm8 + vpaddd ymm0, ymm0, ymmword ptr [rsp+140H] + vpaddd ymm1, ymm1, ymmword ptr [rsp+180H] + vpaddd ymm2, ymm2, ymmword ptr [rsp+80H] + vpaddd ymm3, ymm3, ymmword ptr [rsp+1A0H] + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxor ymm15, ymm15, ymm0 + vpxor ymm12, ymm12, ymm1 + vpxor ymm13, ymm13, ymm2 + vpxor ymm14, ymm14, ymm3 + vbroadcasti128 ymm8, xmmword ptr [ROT8] + vpshufb ymm15, ymm15, ymm8 + vpshufb ymm12, ymm12, ymm8 + vpshufb ymm13, ymm13, ymm8 + vpshufb ymm14, ymm14, ymm8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm13, ymmword ptr [rsp+200H] + vpaddd ymm9, ymm9, ymm14 + vpxor ymm5, ymm5, ymm10 + vpxor ymm6, ymm6, ymm11 + vpxor ymm7, ymm7, ymm8 + vpxor ymm4, ymm4, ymm9 + vpxor ymm0, ymm0, ymm8 + vpxor ymm1, ymm1, ymm9 + vpxor ymm2, ymm2, ymm10 + vpxor ymm3, ymm3, ymm11 + vpsrld ymm8, ymm5, 7 + vpslld ymm5, ymm5, 25 + vpor ymm5, ymm5, ymm8 + vpsrld ymm8, ymm6, 7 + vpslld ymm6, ymm6, 25 + vpor ymm6, ymm6, ymm8 + vpsrld ymm8, ymm7, 7 + vpslld ymm7, ymm7, 25 + vpor ymm7, ymm7, ymm8 + vpsrld ymm8, ymm4, 7 + vpslld ymm4, ymm4, 25 + vpor ymm4, ymm4, ymm8 + vpxor ymm4, ymm4, ymm12 + vpxor ymm5, ymm5, ymm13 + vpxor ymm6, ymm6, ymm14 + vpxor ymm7, ymm7, ymm15 + movzx eax, byte ptr [rbp+78H] + jne innerloop8 + mov rbx, qword ptr [rbp+90H] + vunpcklps ymm8, ymm0, ymm1 + vunpcklps ymm9, ymm2, ymm3 + vunpckhps ymm10, ymm0, ymm1 + vunpcklps ymm11, ymm4, ymm5 + vunpcklps ymm0, ymm6, ymm7 + vshufps ymm12, ymm8, ymm9, 78 + vblendps ymm1, ymm8, ymm12, 0CCH + vshufps ymm8, ymm11, ymm0, 78 + vunpckhps ymm13, ymm2, ymm3 + vblendps ymm2, ymm11, ymm8, 0CCH + vblendps ymm3, ymm12, ymm9, 0CCH + vperm2f128 ymm12, ymm1, ymm2, 20H + vmovups ymmword ptr [rbx], ymm12 + vunpckhps ymm14, ymm4, ymm5 + vblendps ymm4, ymm8, ymm0, 0CCH + vunpckhps ymm15, ymm6, ymm7 + vperm2f128 ymm7, ymm3, ymm4, 20H + vmovups ymmword ptr [rbx+20H], ymm7 + vshufps ymm5, ymm10, ymm13, 78 + vblendps ymm6, ymm5, ymm13, 0CCH + vshufps ymm13, ymm14, ymm15, 78 + vblendps ymm10, ymm10, ymm5, 0CCH + vblendps ymm14, ymm14, ymm13, 0CCH + vperm2f128 ymm8, ymm10, ymm14, 20H + vmovups ymmword ptr [rbx+40H], ymm8 + vblendps ymm15, ymm13, ymm15, 0CCH + vperm2f128 ymm13, ymm6, ymm15, 20H + vmovups ymmword ptr [rbx+60H], ymm13 + vperm2f128 ymm9, ymm1, ymm2, 31H + vperm2f128 ymm11, ymm3, ymm4, 31H + vmovups ymmword ptr [rbx+80H], ymm9 + vperm2f128 ymm14, ymm10, ymm14, 31H + vperm2f128 ymm15, ymm6, ymm15, 31H + vmovups ymmword ptr [rbx+0A0H], ymm11 + vmovups ymmword ptr [rbx+0C0H], ymm14 + vmovups ymmword ptr [rbx+0E0H], ymm15 + vmovdqa ymm0, ymmword ptr [rsp+2A0H] + vpaddd ymm1, ymm0, ymmword ptr [rsp+220H] + vmovdqa ymmword ptr [rsp+220H], ymm1 + vpxor ymm0, ymm0, ymmword ptr [CMP_MSB_MASK] + vpxor ymm2, ymm1, ymmword ptr [CMP_MSB_MASK] + vpcmpgtd ymm2, ymm0, ymm2 + vmovdqa ymm0, ymmword ptr [rsp+240H] + vpsubd ymm2, ymm0, ymm2 + vmovdqa ymmword ptr [rsp+240H], ymm2 + add rdi, 64 + add rbx, 256 + mov qword ptr [rbp+90H], rbx + sub rsi, 8 + cmp rsi, 8 + jnc outerloop8 + test rsi, rsi + jnz final7blocks +unwind: + vzeroupper + vmovdqa xmm6, xmmword ptr [rsp+2D0H] + vmovdqa xmm7, xmmword ptr [rsp+2E0H] + vmovdqa xmm8, xmmword ptr [rsp+2F0H] + vmovdqa xmm9, xmmword ptr [rsp+300H] + vmovdqa xmm10, xmmword ptr [rsp+310H] + vmovdqa xmm11, xmmword ptr [rsp+320H] + vmovdqa xmm12, xmmword ptr [rsp+330H] + vmovdqa xmm13, xmmword ptr [rsp+340H] + vmovdqa xmm14, xmmword ptr [rsp+350H] + vmovdqa xmm15, xmmword ptr [rsp+360H] + mov rsp, rbp + pop rbp + pop rbx + pop rdi + pop rsi + pop r12 + pop r13 + pop r14 + pop r15 + ret +ALIGN 16 +final7blocks: + mov rbx, qword ptr [rbp+90H] + mov r15, qword ptr [rsp+2C0H] + movzx r13d, byte ptr [rbp+78H] + movzx r12d, byte ptr [rbp+88H] + test rsi, 4H + je final3blocks + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+10H] + vmovdqa ymm8, ymm0 + vmovdqa ymm9, ymm1 + vbroadcasti128 ymm12, xmmword ptr [rsp+220H] + vbroadcasti128 ymm13, xmmword ptr [rsp+240H] + vpunpckldq ymm14, ymm12, ymm13 + vpunpckhdq ymm15, ymm12, ymm13 + vpermq ymm14, ymm14, 50H + vpermq ymm15, ymm15, 50H + vbroadcasti128 ymm12, xmmword ptr [BLAKE3_BLOCK_LEN] + vpblendd ymm14, ymm14, ymm12, 44H + vpblendd ymm15, ymm15, ymm12, 44H + vmovdqa ymmword ptr [rsp], ymm14 + vmovdqa ymmword ptr [rsp+20H], ymm15 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + mov r10, qword ptr [rdi+10H] + mov r11, qword ptr [rdi+18H] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +ALIGN 16 +innerloop4: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+200H], eax + vmovups ymm2, ymmword ptr [r8+rdx-40H] + vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-40H], 01H + vmovups ymm3, ymmword ptr [r8+rdx-30H] + vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-30H], 01H + vshufps ymm4, ymm2, ymm3, 136 + vshufps ymm5, ymm2, ymm3, 221 + vmovups ymm2, ymmword ptr [r8+rdx-20H] + vinsertf128 ymm2, ymm2, xmmword ptr [r9+rdx-20H], 01H + vmovups ymm3, ymmword ptr [r8+rdx-10H] + vinsertf128 ymm3, ymm3, xmmword ptr [r9+rdx-10H], 01H + vshufps ymm6, ymm2, ymm3, 136 + vshufps ymm7, ymm2, ymm3, 221 + vpshufd ymm6, ymm6, 93H + vpshufd ymm7, ymm7, 93H + vmovups ymm10, ymmword ptr [r10+rdx-40H] + vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-40H], 01H + vmovups ymm11, ymmword ptr [r10+rdx-30H] + vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-30H], 01H + vshufps ymm12, ymm10, ymm11, 136 + vshufps ymm13, ymm10, ymm11, 221 + vmovups ymm10, ymmword ptr [r10+rdx-20H] + vinsertf128 ymm10, ymm10, xmmword ptr [r11+rdx-20H], 01H + vmovups ymm11, ymmword ptr [r10+rdx-10H] + vinsertf128 ymm11, ymm11, xmmword ptr [r11+rdx-10H], 01H + vshufps ymm14, ymm10, ymm11, 136 + vshufps ymm15, ymm10, ymm11, 221 + vpshufd ymm14, ymm14, 93H + vpshufd ymm15, ymm15, 93H + vpbroadcastd ymm2, dword ptr [rsp+200H] + vmovdqa ymm3, ymmword ptr [rsp] + vmovdqa ymm11, ymmword ptr [rsp+20H] + vpblendd ymm3, ymm3, ymm2, 88H + vpblendd ymm11, ymm11, ymm2, 88H + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV] + vmovdqa ymm10, ymm2 + mov al, 7 +roundloop4: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm8, ymm8, ymm12 + vmovdqa ymmword ptr [rsp+40H], ymm4 + nop + vmovdqa ymmword ptr [rsp+60H], ymm12 + nop + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT16] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 12 + vpslld ymm9, ymm9, 20 + vpor ymm9, ymm9, ymm4 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vmovdqa ymmword ptr [rsp+80H], ymm5 + vmovdqa ymmword ptr [rsp+0A0H], ymm13 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT8] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 7 + vpslld ymm9, ymm9, 25 + vpor ymm9, ymm9, ymm4 + vpshufd ymm0, ymm0, 93H + vpshufd ymm8, ymm8, 93H + vpshufd ymm3, ymm3, 4EH + vpshufd ymm11, ymm11, 4EH + vpshufd ymm2, ymm2, 39H + vpshufd ymm10, ymm10, 39H + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm8, ymm8, ymm14 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT16] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 12 + vpslld ymm9, ymm9, 20 + vpor ymm9, ymm9, ymm4 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm8, ymm8, ymm15 + vpaddd ymm0, ymm0, ymm1 + vpaddd ymm8, ymm8, ymm9 + vpxor ymm3, ymm3, ymm0 + vpxor ymm11, ymm11, ymm8 + vbroadcasti128 ymm4, xmmword ptr [ROT8] + vpshufb ymm3, ymm3, ymm4 + vpshufb ymm11, ymm11, ymm4 + vpaddd ymm2, ymm2, ymm3 + vpaddd ymm10, ymm10, ymm11 + vpxor ymm1, ymm1, ymm2 + vpxor ymm9, ymm9, ymm10 + vpsrld ymm4, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm4 + vpsrld ymm4, ymm9, 7 + vpslld ymm9, ymm9, 25 + vpor ymm9, ymm9, ymm4 + vpshufd ymm0, ymm0, 39H + vpshufd ymm8, ymm8, 39H + vpshufd ymm3, ymm3, 4EH + vpshufd ymm11, ymm11, 4EH + vpshufd ymm2, ymm2, 93H + vpshufd ymm10, ymm10, 93H + dec al + je endroundloop4 + vmovdqa ymm4, ymmword ptr [rsp+40H] + vmovdqa ymm5, ymmword ptr [rsp+80H] + vshufps ymm12, ymm4, ymm5, 214 + vpshufd ymm13, ymm4, 0FH + vpshufd ymm4, ymm12, 39H + vshufps ymm12, ymm6, ymm7, 250 + vpblendd ymm13, ymm13, ymm12, 0AAH + vpunpcklqdq ymm12, ymm7, ymm5 + vpblendd ymm12, ymm12, ymm6, 88H + vpshufd ymm12, ymm12, 78H + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 1EH + vmovdqa ymmword ptr [rsp+40H], ymm13 + vmovdqa ymmword ptr [rsp+80H], ymm12 + vmovdqa ymm12, ymmword ptr [rsp+60H] + vmovdqa ymm13, ymmword ptr [rsp+0A0H] + vshufps ymm5, ymm12, ymm13, 214 + vpshufd ymm6, ymm12, 0FH + vpshufd ymm12, ymm5, 39H + vshufps ymm5, ymm14, ymm15, 250 + vpblendd ymm6, ymm6, ymm5, 0AAH + vpunpcklqdq ymm5, ymm15, ymm13 + vpblendd ymm5, ymm5, ymm14, 88H + vpshufd ymm5, ymm5, 78H + vpunpckhdq ymm13, ymm13, ymm15 + vpunpckldq ymm14, ymm14, ymm13 + vpshufd ymm15, ymm14, 1EH + vmovdqa ymm13, ymm6 + vmovdqa ymm14, ymm5 + vmovdqa ymm5, ymmword ptr [rsp+40H] + vmovdqa ymm6, ymmword ptr [rsp+80H] + jmp roundloop4 +endroundloop4: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + vpxor ymm8, ymm8, ymm10 + vpxor ymm9, ymm9, ymm11 + mov eax, r13d + cmp rdx, r15 + jne innerloop4 + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+10H], xmm1 + vextracti128 xmmword ptr [rbx+20H], ymm0, 01H + vextracti128 xmmword ptr [rbx+30H], ymm1, 01H + vmovdqu xmmword ptr [rbx+40H], xmm8 + vmovdqu xmmword ptr [rbx+50H], xmm9 + vextracti128 xmmword ptr [rbx+60H], ymm8, 01H + vextracti128 xmmword ptr [rbx+70H], ymm9, 01H + vmovaps xmm8, xmmword ptr [rsp+260H] + vmovaps xmm0, xmmword ptr [rsp+220H] + vmovaps xmm1, xmmword ptr [rsp+230H] + vmovaps xmm2, xmmword ptr [rsp+240H] + vmovaps xmm3, xmmword ptr [rsp+250H] + vblendvps xmm0, xmm0, xmm1, xmm8 + vblendvps xmm2, xmm2, xmm3, xmm8 + vmovaps xmmword ptr [rsp+220H], xmm0 + vmovaps xmmword ptr [rsp+240H], xmm2 + add rbx, 128 + add rdi, 32 + sub rsi, 4 +final3blocks: + test rsi, 2H + je final1blocks + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+10H] + vmovd xmm13, dword ptr [rsp+220H] + vpinsrd xmm13, xmm13, dword ptr [rsp+240H], 1 + vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 + vmovd xmm14, dword ptr [rsp+224H] + vpinsrd xmm14, xmm14, dword ptr [rsp+244H], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 + vinserti128 ymm13, ymm13, xmm14, 01H + vbroadcasti128 ymm14, xmmword ptr [ROT16] + vbroadcasti128 ymm15, xmmword ptr [ROT8] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +ALIGN 16 +innerloop2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+200H], eax + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV] + vpbroadcastd ymm8, dword ptr [rsp+200H] + vpblendd ymm3, ymm13, ymm8, 88H + vmovups ymm8, ymmword ptr [r8+rdx-40H] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-40H], 01H + vmovups ymm9, ymmword ptr [r8+rdx-30H] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-30H], 01H + vshufps ymm4, ymm8, ymm9, 136 + vshufps ymm5, ymm8, ymm9, 221 + vmovups ymm8, ymmword ptr [r8+rdx-20H] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-20H], 01H + vmovups ymm9, ymmword ptr [r8+rdx-10H] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-10H], 01H + vshufps ymm6, ymm8, ymm9, 136 + vshufps ymm7, ymm8, ymm9, 221 + vpshufd ymm6, ymm6, 93H + vpshufd ymm7, ymm7, 93H + mov al, 7 +roundloop2: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm14 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm8 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm15 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm8 + vpshufd ymm0, ymm0, 93H + vpshufd ymm3, ymm3, 4EH + vpshufd ymm2, ymm2, 39H + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm14 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 12 + vpslld ymm1, ymm1, 20 + vpor ymm1, ymm1, ymm8 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm0, ymm0, ymm1 + vpxor ymm3, ymm3, ymm0 + vpshufb ymm3, ymm3, ymm15 + vpaddd ymm2, ymm2, ymm3 + vpxor ymm1, ymm1, ymm2 + vpsrld ymm8, ymm1, 7 + vpslld ymm1, ymm1, 25 + vpor ymm1, ymm1, ymm8 + vpshufd ymm0, ymm0, 39H + vpshufd ymm3, ymm3, 4EH + vpshufd ymm2, ymm2, 93H + dec al + jz endroundloop2 + vshufps ymm8, ymm4, ymm5, 214 + vpshufd ymm9, ymm4, 0FH + vpshufd ymm4, ymm8, 39H + vshufps ymm8, ymm6, ymm7, 250 + vpblendd ymm9, ymm9, ymm8, 0AAH + vpunpcklqdq ymm8, ymm7, ymm5 + vpblendd ymm8, ymm8, ymm6, 88H + vpshufd ymm8, ymm8, 78H + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 1EH + vmovdqa ymm5, ymm9 + vmovdqa ymm6, ymm8 + jmp roundloop2 +endroundloop2: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + mov eax, r13d + cmp rdx, r15 + jne innerloop2 + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+10H], xmm1 + vextracti128 xmmword ptr [rbx+20H], ymm0, 01H + vextracti128 xmmword ptr [rbx+30H], ymm1, 01H + vmovaps ymm8, ymmword ptr [rsp+260H] + vmovaps ymm0, ymmword ptr [rsp+220H] + vmovups ymm1, ymmword ptr [rsp+228H] + vmovaps ymm2, ymmword ptr [rsp+240H] + vmovups ymm3, ymmword ptr [rsp+248H] + vblendvps ymm0, ymm0, ymm1, ymm8 + vblendvps ymm2, ymm2, ymm3, ymm8 + vmovaps ymmword ptr [rsp+220H], ymm0 + vmovaps ymmword ptr [rsp+240H], ymm2 + add rbx, 64 + add rdi, 16 + sub rsi, 2 +final1blocks: + test rsi, 1H + je unwind + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+10H] + vmovd xmm3, dword ptr [rsp+220H] + vpinsrd xmm3, xmm3, dword ptr [rsp+240H], 1 + vpinsrd xmm13, xmm3, dword ptr [BLAKE3_BLOCK_LEN], 2 + vmovdqa xmm14, xmmword ptr [ROT16] + vmovdqa xmm15, xmmword ptr [ROT8] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +ALIGN 16 +innerloop1: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + vmovdqa xmm2, xmmword ptr [BLAKE3_IV] + vmovdqa xmm3, xmm13 + vpinsrd xmm3, xmm3, eax, 3 + vmovups xmm8, xmmword ptr [r8+rdx-40H] + vmovups xmm9, xmmword ptr [r8+rdx-30H] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [r8+rdx-20H] + vmovups xmm9, xmmword ptr [r8+rdx-10H] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 93H + vpshufd xmm7, xmm7, 93H + mov al, 7 +roundloop1: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm14 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 12 + vpslld xmm1, xmm1, 20 + vpor xmm1, xmm1, xmm8 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm15 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 7 + vpslld xmm1, xmm1, 25 + vpor xmm1, xmm1, xmm8 + vpshufd xmm0, xmm0, 93H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 39H + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm14 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 12 + vpslld xmm1, xmm1, 20 + vpor xmm1, xmm1, xmm8 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxor xmm3, xmm3, xmm0 + vpshufb xmm3, xmm3, xmm15 + vpaddd xmm2, xmm2, xmm3 + vpxor xmm1, xmm1, xmm2 + vpsrld xmm8, xmm1, 7 + vpslld xmm1, xmm1, 25 + vpor xmm1, xmm1, xmm8 + vpshufd xmm0, xmm0, 39H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 93H + dec al + jz endroundloop1 + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0FH + vpshufd xmm4, xmm8, 39H + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0AAH + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 88H + vpshufd xmm8, xmm8, 78H + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 1EH + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp roundloop1 +endroundloop1: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne innerloop1 + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+10H], xmm1 + jmp unwind + +_blake3_hash_many_avx2 ENDP +blake3_hash_many_avx2 ENDP +_TEXT ENDS + +_RDATA SEGMENT READONLY PAGE ALIAS(".rdata") 'CONST' +ALIGN 64 +ADD0: + dd 0, 1, 2, 3, 4, 5, 6, 7 + +ADD1: + dd 8 dup (8) + +BLAKE3_IV_0: + dd 8 dup (6A09E667H) + +BLAKE3_IV_1: + dd 8 dup (0BB67AE85H) + +BLAKE3_IV_2: + dd 8 dup (3C6EF372H) + +BLAKE3_IV_3: + dd 8 dup (0A54FF53AH) + +BLAKE3_BLOCK_LEN: + dd 8 dup (64) + +ROT16: + db 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 + +ROT8: + db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 + +CMP_MSB_MASK: + dd 8 dup(80000000H) + +BLAKE3_IV: + dd 6A09E667H, 0BB67AE85H, 3C6EF372H, 0A54FF53AH + +_RDATA ENDS +END diff --git a/src/Native/libmultihash/blake3/blake3_avx512.c b/src/Native/libmultihash/blake3/blake3_avx512.c new file mode 100644 index 000000000..77a5c385c --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx512.c @@ -0,0 +1,1204 @@ +#include "blake3_impl.h" + +#include + +#define _mm_shuffle_ps2(a, b, c) \ + (_mm_castps_si128( \ + _mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), (c)))) + +INLINE __m128i loadu_128(const uint8_t src[16]) { + return _mm_loadu_si128((const __m128i *)src); +} + +INLINE __m256i loadu_256(const uint8_t src[32]) { + return _mm256_loadu_si256((const __m256i *)src); +} + +INLINE __m512i loadu_512(const uint8_t src[64]) { + return _mm512_loadu_si512((const __m512i *)src); +} + +INLINE void storeu_128(__m128i src, uint8_t dest[16]) { + _mm_storeu_si128((__m128i *)dest, src); +} + +INLINE void storeu_256(__m256i src, uint8_t dest[16]) { + _mm256_storeu_si256((__m256i *)dest, src); +} + +INLINE __m128i add_128(__m128i a, __m128i b) { return _mm_add_epi32(a, b); } + +INLINE __m256i add_256(__m256i a, __m256i b) { return _mm256_add_epi32(a, b); } + +INLINE __m512i add_512(__m512i a, __m512i b) { return _mm512_add_epi32(a, b); } + +INLINE __m128i xor_128(__m128i a, __m128i b) { return _mm_xor_si128(a, b); } + +INLINE __m256i xor_256(__m256i a, __m256i b) { return _mm256_xor_si256(a, b); } + +INLINE __m512i xor_512(__m512i a, __m512i b) { return _mm512_xor_si512(a, b); } + +INLINE __m128i set1_128(uint32_t x) { return _mm_set1_epi32((int32_t)x); } + +INLINE __m256i set1_256(uint32_t x) { return _mm256_set1_epi32((int32_t)x); } + +INLINE __m512i set1_512(uint32_t x) { return _mm512_set1_epi32((int32_t)x); } + +INLINE __m128i set4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + return _mm_setr_epi32((int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d); +} + +INLINE __m128i rot16_128(__m128i x) { return _mm_ror_epi32(x, 16); } + +INLINE __m256i rot16_256(__m256i x) { return _mm256_ror_epi32(x, 16); } + +INLINE __m512i rot16_512(__m512i x) { return _mm512_ror_epi32(x, 16); } + +INLINE __m128i rot12_128(__m128i x) { return _mm_ror_epi32(x, 12); } + +INLINE __m256i rot12_256(__m256i x) { return _mm256_ror_epi32(x, 12); } + +INLINE __m512i rot12_512(__m512i x) { return _mm512_ror_epi32(x, 12); } + +INLINE __m128i rot8_128(__m128i x) { return _mm_ror_epi32(x, 8); } + +INLINE __m256i rot8_256(__m256i x) { return _mm256_ror_epi32(x, 8); } + +INLINE __m512i rot8_512(__m512i x) { return _mm512_ror_epi32(x, 8); } + +INLINE __m128i rot7_128(__m128i x) { return _mm_ror_epi32(x, 7); } + +INLINE __m256i rot7_256(__m256i x) { return _mm256_ror_epi32(x, 7); } + +INLINE __m512i rot7_512(__m512i x) { return _mm512_ror_epi32(x, 7); } + +/* + * ---------------------------------------------------------------------------- + * compress_avx512 + * ---------------------------------------------------------------------------- + */ + +INLINE void g1(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, + __m128i m) { + *row0 = add_128(add_128(*row0, m), *row1); + *row3 = xor_128(*row3, *row0); + *row3 = rot16_128(*row3); + *row2 = add_128(*row2, *row3); + *row1 = xor_128(*row1, *row2); + *row1 = rot12_128(*row1); +} + +INLINE void g2(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, + __m128i m) { + *row0 = add_128(add_128(*row0, m), *row1); + *row3 = xor_128(*row3, *row0); + *row3 = rot8_128(*row3); + *row2 = add_128(*row2, *row3); + *row1 = xor_128(*row1, *row2); + *row1 = rot7_128(*row1); +} + +// Note the optimization here of leaving row1 as the unrotated row, rather than +// row0. All the message loads below are adjusted to compensate for this. See +// discussion at https://github.com/sneves/blake2-avx2/pull/4 +INLINE void diagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { + *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(2, 1, 0, 3)); + *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); + *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(0, 3, 2, 1)); +} + +INLINE void undiagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { + *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(0, 3, 2, 1)); + *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); + *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(2, 1, 0, 3)); +} + +INLINE void compress_pre(__m128i rows[4], const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags) { + rows[0] = loadu_128((uint8_t *)&cv[0]); + rows[1] = loadu_128((uint8_t *)&cv[4]); + rows[2] = set4(IV[0], IV[1], IV[2], IV[3]); + rows[3] = set4(counter_low(counter), counter_high(counter), + (uint32_t)block_len, (uint32_t)flags); + + __m128i m0 = loadu_128(&block[sizeof(__m128i) * 0]); + __m128i m1 = loadu_128(&block[sizeof(__m128i) * 1]); + __m128i m2 = loadu_128(&block[sizeof(__m128i) * 2]); + __m128i m3 = loadu_128(&block[sizeof(__m128i) * 3]); + + __m128i t0, t1, t2, t3, tt; + + // Round 1. The first round permutes the message words from the original + // input order, into the groups that get mixed in parallel. + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(2, 0, 2, 0)); // 6 4 2 0 + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 3, 1)); // 7 5 3 1 + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(2, 0, 2, 0)); // 14 12 10 8 + t2 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2, 1, 0, 3)); // 12 10 8 14 + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 1, 3, 1)); // 15 13 11 9 + t3 = _mm_shuffle_epi32(t3, _MM_SHUFFLE(2, 1, 0, 3)); // 13 11 9 15 + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 2. This round and all following rounds apply a fixed permutation + // to the message words from the round before. + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 3 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 4 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 5 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 6 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 7 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); +} + +void blake3_compress_xof_avx512(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags, uint8_t out[64]) { + __m128i rows[4]; + compress_pre(rows, cv, block, block_len, counter, flags); + storeu_128(xor_128(rows[0], rows[2]), &out[0]); + storeu_128(xor_128(rows[1], rows[3]), &out[16]); + storeu_128(xor_128(rows[2], loadu_128((uint8_t *)&cv[0])), &out[32]); + storeu_128(xor_128(rows[3], loadu_128((uint8_t *)&cv[4])), &out[48]); +} + +void blake3_compress_in_place_avx512(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags) { + __m128i rows[4]; + compress_pre(rows, cv, block, block_len, counter, flags); + storeu_128(xor_128(rows[0], rows[2]), (uint8_t *)&cv[0]); + storeu_128(xor_128(rows[1], rows[3]), (uint8_t *)&cv[4]); +} + +/* + * ---------------------------------------------------------------------------- + * hash4_avx512 + * ---------------------------------------------------------------------------- + */ + +INLINE void round_fn4(__m128i v[16], __m128i m[16], size_t r) { + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); + v[0] = add_128(v[0], v[4]); + v[1] = add_128(v[1], v[5]); + v[2] = add_128(v[2], v[6]); + v[3] = add_128(v[3], v[7]); + v[12] = xor_128(v[12], v[0]); + v[13] = xor_128(v[13], v[1]); + v[14] = xor_128(v[14], v[2]); + v[15] = xor_128(v[15], v[3]); + v[12] = rot16_128(v[12]); + v[13] = rot16_128(v[13]); + v[14] = rot16_128(v[14]); + v[15] = rot16_128(v[15]); + v[8] = add_128(v[8], v[12]); + v[9] = add_128(v[9], v[13]); + v[10] = add_128(v[10], v[14]); + v[11] = add_128(v[11], v[15]); + v[4] = xor_128(v[4], v[8]); + v[5] = xor_128(v[5], v[9]); + v[6] = xor_128(v[6], v[10]); + v[7] = xor_128(v[7], v[11]); + v[4] = rot12_128(v[4]); + v[5] = rot12_128(v[5]); + v[6] = rot12_128(v[6]); + v[7] = rot12_128(v[7]); + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); + v[0] = add_128(v[0], v[4]); + v[1] = add_128(v[1], v[5]); + v[2] = add_128(v[2], v[6]); + v[3] = add_128(v[3], v[7]); + v[12] = xor_128(v[12], v[0]); + v[13] = xor_128(v[13], v[1]); + v[14] = xor_128(v[14], v[2]); + v[15] = xor_128(v[15], v[3]); + v[12] = rot8_128(v[12]); + v[13] = rot8_128(v[13]); + v[14] = rot8_128(v[14]); + v[15] = rot8_128(v[15]); + v[8] = add_128(v[8], v[12]); + v[9] = add_128(v[9], v[13]); + v[10] = add_128(v[10], v[14]); + v[11] = add_128(v[11], v[15]); + v[4] = xor_128(v[4], v[8]); + v[5] = xor_128(v[5], v[9]); + v[6] = xor_128(v[6], v[10]); + v[7] = xor_128(v[7], v[11]); + v[4] = rot7_128(v[4]); + v[5] = rot7_128(v[5]); + v[6] = rot7_128(v[6]); + v[7] = rot7_128(v[7]); + + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); + v[0] = add_128(v[0], v[5]); + v[1] = add_128(v[1], v[6]); + v[2] = add_128(v[2], v[7]); + v[3] = add_128(v[3], v[4]); + v[15] = xor_128(v[15], v[0]); + v[12] = xor_128(v[12], v[1]); + v[13] = xor_128(v[13], v[2]); + v[14] = xor_128(v[14], v[3]); + v[15] = rot16_128(v[15]); + v[12] = rot16_128(v[12]); + v[13] = rot16_128(v[13]); + v[14] = rot16_128(v[14]); + v[10] = add_128(v[10], v[15]); + v[11] = add_128(v[11], v[12]); + v[8] = add_128(v[8], v[13]); + v[9] = add_128(v[9], v[14]); + v[5] = xor_128(v[5], v[10]); + v[6] = xor_128(v[6], v[11]); + v[7] = xor_128(v[7], v[8]); + v[4] = xor_128(v[4], v[9]); + v[5] = rot12_128(v[5]); + v[6] = rot12_128(v[6]); + v[7] = rot12_128(v[7]); + v[4] = rot12_128(v[4]); + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); + v[0] = add_128(v[0], v[5]); + v[1] = add_128(v[1], v[6]); + v[2] = add_128(v[2], v[7]); + v[3] = add_128(v[3], v[4]); + v[15] = xor_128(v[15], v[0]); + v[12] = xor_128(v[12], v[1]); + v[13] = xor_128(v[13], v[2]); + v[14] = xor_128(v[14], v[3]); + v[15] = rot8_128(v[15]); + v[12] = rot8_128(v[12]); + v[13] = rot8_128(v[13]); + v[14] = rot8_128(v[14]); + v[10] = add_128(v[10], v[15]); + v[11] = add_128(v[11], v[12]); + v[8] = add_128(v[8], v[13]); + v[9] = add_128(v[9], v[14]); + v[5] = xor_128(v[5], v[10]); + v[6] = xor_128(v[6], v[11]); + v[7] = xor_128(v[7], v[8]); + v[4] = xor_128(v[4], v[9]); + v[5] = rot7_128(v[5]); + v[6] = rot7_128(v[6]); + v[7] = rot7_128(v[7]); + v[4] = rot7_128(v[4]); +} + +INLINE void transpose_vecs_128(__m128i vecs[4]) { + // Interleave 32-bit lates. The low unpack is lanes 00/11 and the high is + // 22/33. Note that this doesn't split the vector into two lanes, as the + // AVX2 counterparts do. + __m128i ab_01 = _mm_unpacklo_epi32(vecs[0], vecs[1]); + __m128i ab_23 = _mm_unpackhi_epi32(vecs[0], vecs[1]); + __m128i cd_01 = _mm_unpacklo_epi32(vecs[2], vecs[3]); + __m128i cd_23 = _mm_unpackhi_epi32(vecs[2], vecs[3]); + + // Interleave 64-bit lanes. + __m128i abcd_0 = _mm_unpacklo_epi64(ab_01, cd_01); + __m128i abcd_1 = _mm_unpackhi_epi64(ab_01, cd_01); + __m128i abcd_2 = _mm_unpacklo_epi64(ab_23, cd_23); + __m128i abcd_3 = _mm_unpackhi_epi64(ab_23, cd_23); + + vecs[0] = abcd_0; + vecs[1] = abcd_1; + vecs[2] = abcd_2; + vecs[3] = abcd_3; +} + +INLINE void transpose_msg_vecs4(const uint8_t *const *inputs, + size_t block_offset, __m128i out[16]) { + out[0] = loadu_128(&inputs[0][block_offset + 0 * sizeof(__m128i)]); + out[1] = loadu_128(&inputs[1][block_offset + 0 * sizeof(__m128i)]); + out[2] = loadu_128(&inputs[2][block_offset + 0 * sizeof(__m128i)]); + out[3] = loadu_128(&inputs[3][block_offset + 0 * sizeof(__m128i)]); + out[4] = loadu_128(&inputs[0][block_offset + 1 * sizeof(__m128i)]); + out[5] = loadu_128(&inputs[1][block_offset + 1 * sizeof(__m128i)]); + out[6] = loadu_128(&inputs[2][block_offset + 1 * sizeof(__m128i)]); + out[7] = loadu_128(&inputs[3][block_offset + 1 * sizeof(__m128i)]); + out[8] = loadu_128(&inputs[0][block_offset + 2 * sizeof(__m128i)]); + out[9] = loadu_128(&inputs[1][block_offset + 2 * sizeof(__m128i)]); + out[10] = loadu_128(&inputs[2][block_offset + 2 * sizeof(__m128i)]); + out[11] = loadu_128(&inputs[3][block_offset + 2 * sizeof(__m128i)]); + out[12] = loadu_128(&inputs[0][block_offset + 3 * sizeof(__m128i)]); + out[13] = loadu_128(&inputs[1][block_offset + 3 * sizeof(__m128i)]); + out[14] = loadu_128(&inputs[2][block_offset + 3 * sizeof(__m128i)]); + out[15] = loadu_128(&inputs[3][block_offset + 3 * sizeof(__m128i)]); + for (size_t i = 0; i < 4; ++i) { + _mm_prefetch(&inputs[i][block_offset + 256], _MM_HINT_T0); + } + transpose_vecs_128(&out[0]); + transpose_vecs_128(&out[4]); + transpose_vecs_128(&out[8]); + transpose_vecs_128(&out[12]); +} + +INLINE void load_counters4(uint64_t counter, bool increment_counter, + __m128i *out_lo, __m128i *out_hi) { + uint64_t mask = (increment_counter ? ~0 : 0); + __m256i mask_vec = _mm256_set1_epi64x(mask); + __m256i deltas = _mm256_setr_epi64x(0, 1, 2, 3); + deltas = _mm256_and_si256(mask_vec, deltas); + __m256i counters = + _mm256_add_epi64(_mm256_set1_epi64x((int64_t)counter), deltas); + *out_lo = _mm256_cvtepi64_epi32(counters); + *out_hi = _mm256_cvtepi64_epi32(_mm256_srli_epi64(counters, 32)); +} + +void blake3_hash4_avx512(const uint8_t *const *inputs, size_t blocks, + const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, uint8_t *out) { + __m128i h_vecs[8] = { + set1_128(key[0]), set1_128(key[1]), set1_128(key[2]), set1_128(key[3]), + set1_128(key[4]), set1_128(key[5]), set1_128(key[6]), set1_128(key[7]), + }; + __m128i counter_low_vec, counter_high_vec; + load_counters4(counter, increment_counter, &counter_low_vec, + &counter_high_vec); + uint8_t block_flags = flags | flags_start; + + for (size_t block = 0; block < blocks; block++) { + if (block + 1 == blocks) { + block_flags |= flags_end; + } + __m128i block_len_vec = set1_128(BLAKE3_BLOCK_LEN); + __m128i block_flags_vec = set1_128(block_flags); + __m128i msg_vecs[16]; + transpose_msg_vecs4(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); + + __m128i v[16] = { + h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], + h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], + set1_128(IV[0]), set1_128(IV[1]), set1_128(IV[2]), set1_128(IV[3]), + counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, + }; + round_fn4(v, msg_vecs, 0); + round_fn4(v, msg_vecs, 1); + round_fn4(v, msg_vecs, 2); + round_fn4(v, msg_vecs, 3); + round_fn4(v, msg_vecs, 4); + round_fn4(v, msg_vecs, 5); + round_fn4(v, msg_vecs, 6); + h_vecs[0] = xor_128(v[0], v[8]); + h_vecs[1] = xor_128(v[1], v[9]); + h_vecs[2] = xor_128(v[2], v[10]); + h_vecs[3] = xor_128(v[3], v[11]); + h_vecs[4] = xor_128(v[4], v[12]); + h_vecs[5] = xor_128(v[5], v[13]); + h_vecs[6] = xor_128(v[6], v[14]); + h_vecs[7] = xor_128(v[7], v[15]); + + block_flags = flags; + } + + transpose_vecs_128(&h_vecs[0]); + transpose_vecs_128(&h_vecs[4]); + // The first four vecs now contain the first half of each output, and the + // second four vecs contain the second half of each output. + storeu_128(h_vecs[0], &out[0 * sizeof(__m128i)]); + storeu_128(h_vecs[4], &out[1 * sizeof(__m128i)]); + storeu_128(h_vecs[1], &out[2 * sizeof(__m128i)]); + storeu_128(h_vecs[5], &out[3 * sizeof(__m128i)]); + storeu_128(h_vecs[2], &out[4 * sizeof(__m128i)]); + storeu_128(h_vecs[6], &out[5 * sizeof(__m128i)]); + storeu_128(h_vecs[3], &out[6 * sizeof(__m128i)]); + storeu_128(h_vecs[7], &out[7 * sizeof(__m128i)]); +} + +/* + * ---------------------------------------------------------------------------- + * hash8_avx512 + * ---------------------------------------------------------------------------- + */ + +INLINE void round_fn8(__m256i v[16], __m256i m[16], size_t r) { + v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); + v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); + v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); + v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); + v[0] = add_256(v[0], v[4]); + v[1] = add_256(v[1], v[5]); + v[2] = add_256(v[2], v[6]); + v[3] = add_256(v[3], v[7]); + v[12] = xor_256(v[12], v[0]); + v[13] = xor_256(v[13], v[1]); + v[14] = xor_256(v[14], v[2]); + v[15] = xor_256(v[15], v[3]); + v[12] = rot16_256(v[12]); + v[13] = rot16_256(v[13]); + v[14] = rot16_256(v[14]); + v[15] = rot16_256(v[15]); + v[8] = add_256(v[8], v[12]); + v[9] = add_256(v[9], v[13]); + v[10] = add_256(v[10], v[14]); + v[11] = add_256(v[11], v[15]); + v[4] = xor_256(v[4], v[8]); + v[5] = xor_256(v[5], v[9]); + v[6] = xor_256(v[6], v[10]); + v[7] = xor_256(v[7], v[11]); + v[4] = rot12_256(v[4]); + v[5] = rot12_256(v[5]); + v[6] = rot12_256(v[6]); + v[7] = rot12_256(v[7]); + v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); + v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); + v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); + v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); + v[0] = add_256(v[0], v[4]); + v[1] = add_256(v[1], v[5]); + v[2] = add_256(v[2], v[6]); + v[3] = add_256(v[3], v[7]); + v[12] = xor_256(v[12], v[0]); + v[13] = xor_256(v[13], v[1]); + v[14] = xor_256(v[14], v[2]); + v[15] = xor_256(v[15], v[3]); + v[12] = rot8_256(v[12]); + v[13] = rot8_256(v[13]); + v[14] = rot8_256(v[14]); + v[15] = rot8_256(v[15]); + v[8] = add_256(v[8], v[12]); + v[9] = add_256(v[9], v[13]); + v[10] = add_256(v[10], v[14]); + v[11] = add_256(v[11], v[15]); + v[4] = xor_256(v[4], v[8]); + v[5] = xor_256(v[5], v[9]); + v[6] = xor_256(v[6], v[10]); + v[7] = xor_256(v[7], v[11]); + v[4] = rot7_256(v[4]); + v[5] = rot7_256(v[5]); + v[6] = rot7_256(v[6]); + v[7] = rot7_256(v[7]); + + v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); + v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); + v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); + v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); + v[0] = add_256(v[0], v[5]); + v[1] = add_256(v[1], v[6]); + v[2] = add_256(v[2], v[7]); + v[3] = add_256(v[3], v[4]); + v[15] = xor_256(v[15], v[0]); + v[12] = xor_256(v[12], v[1]); + v[13] = xor_256(v[13], v[2]); + v[14] = xor_256(v[14], v[3]); + v[15] = rot16_256(v[15]); + v[12] = rot16_256(v[12]); + v[13] = rot16_256(v[13]); + v[14] = rot16_256(v[14]); + v[10] = add_256(v[10], v[15]); + v[11] = add_256(v[11], v[12]); + v[8] = add_256(v[8], v[13]); + v[9] = add_256(v[9], v[14]); + v[5] = xor_256(v[5], v[10]); + v[6] = xor_256(v[6], v[11]); + v[7] = xor_256(v[7], v[8]); + v[4] = xor_256(v[4], v[9]); + v[5] = rot12_256(v[5]); + v[6] = rot12_256(v[6]); + v[7] = rot12_256(v[7]); + v[4] = rot12_256(v[4]); + v[0] = add_256(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); + v[1] = add_256(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); + v[2] = add_256(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); + v[3] = add_256(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); + v[0] = add_256(v[0], v[5]); + v[1] = add_256(v[1], v[6]); + v[2] = add_256(v[2], v[7]); + v[3] = add_256(v[3], v[4]); + v[15] = xor_256(v[15], v[0]); + v[12] = xor_256(v[12], v[1]); + v[13] = xor_256(v[13], v[2]); + v[14] = xor_256(v[14], v[3]); + v[15] = rot8_256(v[15]); + v[12] = rot8_256(v[12]); + v[13] = rot8_256(v[13]); + v[14] = rot8_256(v[14]); + v[10] = add_256(v[10], v[15]); + v[11] = add_256(v[11], v[12]); + v[8] = add_256(v[8], v[13]); + v[9] = add_256(v[9], v[14]); + v[5] = xor_256(v[5], v[10]); + v[6] = xor_256(v[6], v[11]); + v[7] = xor_256(v[7], v[8]); + v[4] = xor_256(v[4], v[9]); + v[5] = rot7_256(v[5]); + v[6] = rot7_256(v[6]); + v[7] = rot7_256(v[7]); + v[4] = rot7_256(v[4]); +} + +INLINE void transpose_vecs_256(__m256i vecs[8]) { + // Interleave 32-bit lanes. The low unpack is lanes 00/11/44/55, and the high + // is 22/33/66/77. + __m256i ab_0145 = _mm256_unpacklo_epi32(vecs[0], vecs[1]); + __m256i ab_2367 = _mm256_unpackhi_epi32(vecs[0], vecs[1]); + __m256i cd_0145 = _mm256_unpacklo_epi32(vecs[2], vecs[3]); + __m256i cd_2367 = _mm256_unpackhi_epi32(vecs[2], vecs[3]); + __m256i ef_0145 = _mm256_unpacklo_epi32(vecs[4], vecs[5]); + __m256i ef_2367 = _mm256_unpackhi_epi32(vecs[4], vecs[5]); + __m256i gh_0145 = _mm256_unpacklo_epi32(vecs[6], vecs[7]); + __m256i gh_2367 = _mm256_unpackhi_epi32(vecs[6], vecs[7]); + + // Interleave 64-bit lates. The low unpack is lanes 00/22 and the high is + // 11/33. + __m256i abcd_04 = _mm256_unpacklo_epi64(ab_0145, cd_0145); + __m256i abcd_15 = _mm256_unpackhi_epi64(ab_0145, cd_0145); + __m256i abcd_26 = _mm256_unpacklo_epi64(ab_2367, cd_2367); + __m256i abcd_37 = _mm256_unpackhi_epi64(ab_2367, cd_2367); + __m256i efgh_04 = _mm256_unpacklo_epi64(ef_0145, gh_0145); + __m256i efgh_15 = _mm256_unpackhi_epi64(ef_0145, gh_0145); + __m256i efgh_26 = _mm256_unpacklo_epi64(ef_2367, gh_2367); + __m256i efgh_37 = _mm256_unpackhi_epi64(ef_2367, gh_2367); + + // Interleave 128-bit lanes. + vecs[0] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x20); + vecs[1] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x20); + vecs[2] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x20); + vecs[3] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x20); + vecs[4] = _mm256_permute2x128_si256(abcd_04, efgh_04, 0x31); + vecs[5] = _mm256_permute2x128_si256(abcd_15, efgh_15, 0x31); + vecs[6] = _mm256_permute2x128_si256(abcd_26, efgh_26, 0x31); + vecs[7] = _mm256_permute2x128_si256(abcd_37, efgh_37, 0x31); +} + +INLINE void transpose_msg_vecs8(const uint8_t *const *inputs, + size_t block_offset, __m256i out[16]) { + out[0] = loadu_256(&inputs[0][block_offset + 0 * sizeof(__m256i)]); + out[1] = loadu_256(&inputs[1][block_offset + 0 * sizeof(__m256i)]); + out[2] = loadu_256(&inputs[2][block_offset + 0 * sizeof(__m256i)]); + out[3] = loadu_256(&inputs[3][block_offset + 0 * sizeof(__m256i)]); + out[4] = loadu_256(&inputs[4][block_offset + 0 * sizeof(__m256i)]); + out[5] = loadu_256(&inputs[5][block_offset + 0 * sizeof(__m256i)]); + out[6] = loadu_256(&inputs[6][block_offset + 0 * sizeof(__m256i)]); + out[7] = loadu_256(&inputs[7][block_offset + 0 * sizeof(__m256i)]); + out[8] = loadu_256(&inputs[0][block_offset + 1 * sizeof(__m256i)]); + out[9] = loadu_256(&inputs[1][block_offset + 1 * sizeof(__m256i)]); + out[10] = loadu_256(&inputs[2][block_offset + 1 * sizeof(__m256i)]); + out[11] = loadu_256(&inputs[3][block_offset + 1 * sizeof(__m256i)]); + out[12] = loadu_256(&inputs[4][block_offset + 1 * sizeof(__m256i)]); + out[13] = loadu_256(&inputs[5][block_offset + 1 * sizeof(__m256i)]); + out[14] = loadu_256(&inputs[6][block_offset + 1 * sizeof(__m256i)]); + out[15] = loadu_256(&inputs[7][block_offset + 1 * sizeof(__m256i)]); + for (size_t i = 0; i < 8; ++i) { + _mm_prefetch(&inputs[i][block_offset + 256], _MM_HINT_T0); + } + transpose_vecs_256(&out[0]); + transpose_vecs_256(&out[8]); +} + +INLINE void load_counters8(uint64_t counter, bool increment_counter, + __m256i *out_lo, __m256i *out_hi) { + uint64_t mask = (increment_counter ? ~0 : 0); + __m512i mask_vec = _mm512_set1_epi64(mask); + __m512i deltas = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + deltas = _mm512_and_si512(mask_vec, deltas); + __m512i counters = + _mm512_add_epi64(_mm512_set1_epi64((int64_t)counter), deltas); + *out_lo = _mm512_cvtepi64_epi32(counters); + *out_hi = _mm512_cvtepi64_epi32(_mm512_srli_epi64(counters, 32)); +} + +void blake3_hash8_avx512(const uint8_t *const *inputs, size_t blocks, + const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, uint8_t *out) { + __m256i h_vecs[8] = { + set1_256(key[0]), set1_256(key[1]), set1_256(key[2]), set1_256(key[3]), + set1_256(key[4]), set1_256(key[5]), set1_256(key[6]), set1_256(key[7]), + }; + __m256i counter_low_vec, counter_high_vec; + load_counters8(counter, increment_counter, &counter_low_vec, + &counter_high_vec); + uint8_t block_flags = flags | flags_start; + + for (size_t block = 0; block < blocks; block++) { + if (block + 1 == blocks) { + block_flags |= flags_end; + } + __m256i block_len_vec = set1_256(BLAKE3_BLOCK_LEN); + __m256i block_flags_vec = set1_256(block_flags); + __m256i msg_vecs[16]; + transpose_msg_vecs8(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); + + __m256i v[16] = { + h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], + h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], + set1_256(IV[0]), set1_256(IV[1]), set1_256(IV[2]), set1_256(IV[3]), + counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, + }; + round_fn8(v, msg_vecs, 0); + round_fn8(v, msg_vecs, 1); + round_fn8(v, msg_vecs, 2); + round_fn8(v, msg_vecs, 3); + round_fn8(v, msg_vecs, 4); + round_fn8(v, msg_vecs, 5); + round_fn8(v, msg_vecs, 6); + h_vecs[0] = xor_256(v[0], v[8]); + h_vecs[1] = xor_256(v[1], v[9]); + h_vecs[2] = xor_256(v[2], v[10]); + h_vecs[3] = xor_256(v[3], v[11]); + h_vecs[4] = xor_256(v[4], v[12]); + h_vecs[5] = xor_256(v[5], v[13]); + h_vecs[6] = xor_256(v[6], v[14]); + h_vecs[7] = xor_256(v[7], v[15]); + + block_flags = flags; + } + + transpose_vecs_256(h_vecs); + storeu_256(h_vecs[0], &out[0 * sizeof(__m256i)]); + storeu_256(h_vecs[1], &out[1 * sizeof(__m256i)]); + storeu_256(h_vecs[2], &out[2 * sizeof(__m256i)]); + storeu_256(h_vecs[3], &out[3 * sizeof(__m256i)]); + storeu_256(h_vecs[4], &out[4 * sizeof(__m256i)]); + storeu_256(h_vecs[5], &out[5 * sizeof(__m256i)]); + storeu_256(h_vecs[6], &out[6 * sizeof(__m256i)]); + storeu_256(h_vecs[7], &out[7 * sizeof(__m256i)]); +} + +/* + * ---------------------------------------------------------------------------- + * hash16_avx512 + * ---------------------------------------------------------------------------- + */ + +INLINE void round_fn16(__m512i v[16], __m512i m[16], size_t r) { + v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); + v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); + v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); + v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); + v[0] = add_512(v[0], v[4]); + v[1] = add_512(v[1], v[5]); + v[2] = add_512(v[2], v[6]); + v[3] = add_512(v[3], v[7]); + v[12] = xor_512(v[12], v[0]); + v[13] = xor_512(v[13], v[1]); + v[14] = xor_512(v[14], v[2]); + v[15] = xor_512(v[15], v[3]); + v[12] = rot16_512(v[12]); + v[13] = rot16_512(v[13]); + v[14] = rot16_512(v[14]); + v[15] = rot16_512(v[15]); + v[8] = add_512(v[8], v[12]); + v[9] = add_512(v[9], v[13]); + v[10] = add_512(v[10], v[14]); + v[11] = add_512(v[11], v[15]); + v[4] = xor_512(v[4], v[8]); + v[5] = xor_512(v[5], v[9]); + v[6] = xor_512(v[6], v[10]); + v[7] = xor_512(v[7], v[11]); + v[4] = rot12_512(v[4]); + v[5] = rot12_512(v[5]); + v[6] = rot12_512(v[6]); + v[7] = rot12_512(v[7]); + v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); + v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); + v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); + v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); + v[0] = add_512(v[0], v[4]); + v[1] = add_512(v[1], v[5]); + v[2] = add_512(v[2], v[6]); + v[3] = add_512(v[3], v[7]); + v[12] = xor_512(v[12], v[0]); + v[13] = xor_512(v[13], v[1]); + v[14] = xor_512(v[14], v[2]); + v[15] = xor_512(v[15], v[3]); + v[12] = rot8_512(v[12]); + v[13] = rot8_512(v[13]); + v[14] = rot8_512(v[14]); + v[15] = rot8_512(v[15]); + v[8] = add_512(v[8], v[12]); + v[9] = add_512(v[9], v[13]); + v[10] = add_512(v[10], v[14]); + v[11] = add_512(v[11], v[15]); + v[4] = xor_512(v[4], v[8]); + v[5] = xor_512(v[5], v[9]); + v[6] = xor_512(v[6], v[10]); + v[7] = xor_512(v[7], v[11]); + v[4] = rot7_512(v[4]); + v[5] = rot7_512(v[5]); + v[6] = rot7_512(v[6]); + v[7] = rot7_512(v[7]); + + v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); + v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); + v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); + v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); + v[0] = add_512(v[0], v[5]); + v[1] = add_512(v[1], v[6]); + v[2] = add_512(v[2], v[7]); + v[3] = add_512(v[3], v[4]); + v[15] = xor_512(v[15], v[0]); + v[12] = xor_512(v[12], v[1]); + v[13] = xor_512(v[13], v[2]); + v[14] = xor_512(v[14], v[3]); + v[15] = rot16_512(v[15]); + v[12] = rot16_512(v[12]); + v[13] = rot16_512(v[13]); + v[14] = rot16_512(v[14]); + v[10] = add_512(v[10], v[15]); + v[11] = add_512(v[11], v[12]); + v[8] = add_512(v[8], v[13]); + v[9] = add_512(v[9], v[14]); + v[5] = xor_512(v[5], v[10]); + v[6] = xor_512(v[6], v[11]); + v[7] = xor_512(v[7], v[8]); + v[4] = xor_512(v[4], v[9]); + v[5] = rot12_512(v[5]); + v[6] = rot12_512(v[6]); + v[7] = rot12_512(v[7]); + v[4] = rot12_512(v[4]); + v[0] = add_512(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); + v[1] = add_512(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); + v[2] = add_512(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); + v[3] = add_512(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); + v[0] = add_512(v[0], v[5]); + v[1] = add_512(v[1], v[6]); + v[2] = add_512(v[2], v[7]); + v[3] = add_512(v[3], v[4]); + v[15] = xor_512(v[15], v[0]); + v[12] = xor_512(v[12], v[1]); + v[13] = xor_512(v[13], v[2]); + v[14] = xor_512(v[14], v[3]); + v[15] = rot8_512(v[15]); + v[12] = rot8_512(v[12]); + v[13] = rot8_512(v[13]); + v[14] = rot8_512(v[14]); + v[10] = add_512(v[10], v[15]); + v[11] = add_512(v[11], v[12]); + v[8] = add_512(v[8], v[13]); + v[9] = add_512(v[9], v[14]); + v[5] = xor_512(v[5], v[10]); + v[6] = xor_512(v[6], v[11]); + v[7] = xor_512(v[7], v[8]); + v[4] = xor_512(v[4], v[9]); + v[5] = rot7_512(v[5]); + v[6] = rot7_512(v[6]); + v[7] = rot7_512(v[7]); + v[4] = rot7_512(v[4]); +} + +// 0b10001000, or lanes a0/a2/b0/b2 in little-endian order +#define LO_IMM8 0x88 + +INLINE __m512i unpack_lo_128(__m512i a, __m512i b) { + return _mm512_shuffle_i32x4(a, b, LO_IMM8); +} + +// 0b11011101, or lanes a1/a3/b1/b3 in little-endian order +#define HI_IMM8 0xdd + +INLINE __m512i unpack_hi_128(__m512i a, __m512i b) { + return _mm512_shuffle_i32x4(a, b, HI_IMM8); +} + +INLINE void transpose_vecs_512(__m512i vecs[16]) { + // Interleave 32-bit lanes. The _0 unpack is lanes + // 0/0/1/1/4/4/5/5/8/8/9/9/12/12/13/13, and the _2 unpack is lanes + // 2/2/3/3/6/6/7/7/10/10/11/11/14/14/15/15. + __m512i ab_0 = _mm512_unpacklo_epi32(vecs[0], vecs[1]); + __m512i ab_2 = _mm512_unpackhi_epi32(vecs[0], vecs[1]); + __m512i cd_0 = _mm512_unpacklo_epi32(vecs[2], vecs[3]); + __m512i cd_2 = _mm512_unpackhi_epi32(vecs[2], vecs[3]); + __m512i ef_0 = _mm512_unpacklo_epi32(vecs[4], vecs[5]); + __m512i ef_2 = _mm512_unpackhi_epi32(vecs[4], vecs[5]); + __m512i gh_0 = _mm512_unpacklo_epi32(vecs[6], vecs[7]); + __m512i gh_2 = _mm512_unpackhi_epi32(vecs[6], vecs[7]); + __m512i ij_0 = _mm512_unpacklo_epi32(vecs[8], vecs[9]); + __m512i ij_2 = _mm512_unpackhi_epi32(vecs[8], vecs[9]); + __m512i kl_0 = _mm512_unpacklo_epi32(vecs[10], vecs[11]); + __m512i kl_2 = _mm512_unpackhi_epi32(vecs[10], vecs[11]); + __m512i mn_0 = _mm512_unpacklo_epi32(vecs[12], vecs[13]); + __m512i mn_2 = _mm512_unpackhi_epi32(vecs[12], vecs[13]); + __m512i op_0 = _mm512_unpacklo_epi32(vecs[14], vecs[15]); + __m512i op_2 = _mm512_unpackhi_epi32(vecs[14], vecs[15]); + + // Interleave 64-bit lates. The _0 unpack is lanes + // 0/0/0/0/4/4/4/4/8/8/8/8/12/12/12/12, the _1 unpack is lanes + // 1/1/1/1/5/5/5/5/9/9/9/9/13/13/13/13, the _2 unpack is lanes + // 2/2/2/2/6/6/6/6/10/10/10/10/14/14/14/14, and the _3 unpack is lanes + // 3/3/3/3/7/7/7/7/11/11/11/11/15/15/15/15. + __m512i abcd_0 = _mm512_unpacklo_epi64(ab_0, cd_0); + __m512i abcd_1 = _mm512_unpackhi_epi64(ab_0, cd_0); + __m512i abcd_2 = _mm512_unpacklo_epi64(ab_2, cd_2); + __m512i abcd_3 = _mm512_unpackhi_epi64(ab_2, cd_2); + __m512i efgh_0 = _mm512_unpacklo_epi64(ef_0, gh_0); + __m512i efgh_1 = _mm512_unpackhi_epi64(ef_0, gh_0); + __m512i efgh_2 = _mm512_unpacklo_epi64(ef_2, gh_2); + __m512i efgh_3 = _mm512_unpackhi_epi64(ef_2, gh_2); + __m512i ijkl_0 = _mm512_unpacklo_epi64(ij_0, kl_0); + __m512i ijkl_1 = _mm512_unpackhi_epi64(ij_0, kl_0); + __m512i ijkl_2 = _mm512_unpacklo_epi64(ij_2, kl_2); + __m512i ijkl_3 = _mm512_unpackhi_epi64(ij_2, kl_2); + __m512i mnop_0 = _mm512_unpacklo_epi64(mn_0, op_0); + __m512i mnop_1 = _mm512_unpackhi_epi64(mn_0, op_0); + __m512i mnop_2 = _mm512_unpacklo_epi64(mn_2, op_2); + __m512i mnop_3 = _mm512_unpackhi_epi64(mn_2, op_2); + + // Interleave 128-bit lanes. The _0 unpack is + // 0/0/0/0/8/8/8/8/0/0/0/0/8/8/8/8, the _1 unpack is + // 1/1/1/1/9/9/9/9/1/1/1/1/9/9/9/9, and so on. + __m512i abcdefgh_0 = unpack_lo_128(abcd_0, efgh_0); + __m512i abcdefgh_1 = unpack_lo_128(abcd_1, efgh_1); + __m512i abcdefgh_2 = unpack_lo_128(abcd_2, efgh_2); + __m512i abcdefgh_3 = unpack_lo_128(abcd_3, efgh_3); + __m512i abcdefgh_4 = unpack_hi_128(abcd_0, efgh_0); + __m512i abcdefgh_5 = unpack_hi_128(abcd_1, efgh_1); + __m512i abcdefgh_6 = unpack_hi_128(abcd_2, efgh_2); + __m512i abcdefgh_7 = unpack_hi_128(abcd_3, efgh_3); + __m512i ijklmnop_0 = unpack_lo_128(ijkl_0, mnop_0); + __m512i ijklmnop_1 = unpack_lo_128(ijkl_1, mnop_1); + __m512i ijklmnop_2 = unpack_lo_128(ijkl_2, mnop_2); + __m512i ijklmnop_3 = unpack_lo_128(ijkl_3, mnop_3); + __m512i ijklmnop_4 = unpack_hi_128(ijkl_0, mnop_0); + __m512i ijklmnop_5 = unpack_hi_128(ijkl_1, mnop_1); + __m512i ijklmnop_6 = unpack_hi_128(ijkl_2, mnop_2); + __m512i ijklmnop_7 = unpack_hi_128(ijkl_3, mnop_3); + + // Interleave 128-bit lanes again for the final outputs. + vecs[0] = unpack_lo_128(abcdefgh_0, ijklmnop_0); + vecs[1] = unpack_lo_128(abcdefgh_1, ijklmnop_1); + vecs[2] = unpack_lo_128(abcdefgh_2, ijklmnop_2); + vecs[3] = unpack_lo_128(abcdefgh_3, ijklmnop_3); + vecs[4] = unpack_lo_128(abcdefgh_4, ijklmnop_4); + vecs[5] = unpack_lo_128(abcdefgh_5, ijklmnop_5); + vecs[6] = unpack_lo_128(abcdefgh_6, ijklmnop_6); + vecs[7] = unpack_lo_128(abcdefgh_7, ijklmnop_7); + vecs[8] = unpack_hi_128(abcdefgh_0, ijklmnop_0); + vecs[9] = unpack_hi_128(abcdefgh_1, ijklmnop_1); + vecs[10] = unpack_hi_128(abcdefgh_2, ijklmnop_2); + vecs[11] = unpack_hi_128(abcdefgh_3, ijklmnop_3); + vecs[12] = unpack_hi_128(abcdefgh_4, ijklmnop_4); + vecs[13] = unpack_hi_128(abcdefgh_5, ijklmnop_5); + vecs[14] = unpack_hi_128(abcdefgh_6, ijklmnop_6); + vecs[15] = unpack_hi_128(abcdefgh_7, ijklmnop_7); +} + +INLINE void transpose_msg_vecs16(const uint8_t *const *inputs, + size_t block_offset, __m512i out[16]) { + out[0] = loadu_512(&inputs[0][block_offset]); + out[1] = loadu_512(&inputs[1][block_offset]); + out[2] = loadu_512(&inputs[2][block_offset]); + out[3] = loadu_512(&inputs[3][block_offset]); + out[4] = loadu_512(&inputs[4][block_offset]); + out[5] = loadu_512(&inputs[5][block_offset]); + out[6] = loadu_512(&inputs[6][block_offset]); + out[7] = loadu_512(&inputs[7][block_offset]); + out[8] = loadu_512(&inputs[8][block_offset]); + out[9] = loadu_512(&inputs[9][block_offset]); + out[10] = loadu_512(&inputs[10][block_offset]); + out[11] = loadu_512(&inputs[11][block_offset]); + out[12] = loadu_512(&inputs[12][block_offset]); + out[13] = loadu_512(&inputs[13][block_offset]); + out[14] = loadu_512(&inputs[14][block_offset]); + out[15] = loadu_512(&inputs[15][block_offset]); + for (size_t i = 0; i < 16; ++i) { + _mm_prefetch(&inputs[i][block_offset + 256], _MM_HINT_T0); + } + transpose_vecs_512(out); +} + +INLINE void load_counters16(uint64_t counter, bool increment_counter, + __m512i *out_lo, __m512i *out_hi) { + const __m512i mask = _mm512_set1_epi32(-(int32_t)increment_counter); + const __m512i add0 = _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + const __m512i add1 = _mm512_and_si512(mask, add0); + __m512i l = _mm512_add_epi32(_mm512_set1_epi32(counter), add1); + __mmask16 carry = _mm512_cmp_epu32_mask(l, add1, _MM_CMPINT_LT); + __m512i h = _mm512_mask_add_epi32(_mm512_set1_epi32(counter >> 32), carry, _mm512_set1_epi32(counter >> 32), _mm512_set1_epi32(1)); + *out_lo = l; + *out_hi = h; +} + +void blake3_hash16_avx512(const uint8_t *const *inputs, size_t blocks, + const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, + uint8_t *out) { + __m512i h_vecs[8] = { + set1_512(key[0]), set1_512(key[1]), set1_512(key[2]), set1_512(key[3]), + set1_512(key[4]), set1_512(key[5]), set1_512(key[6]), set1_512(key[7]), + }; + __m512i counter_low_vec, counter_high_vec; + load_counters16(counter, increment_counter, &counter_low_vec, + &counter_high_vec); + uint8_t block_flags = flags | flags_start; + + for (size_t block = 0; block < blocks; block++) { + if (block + 1 == blocks) { + block_flags |= flags_end; + } + __m512i block_len_vec = set1_512(BLAKE3_BLOCK_LEN); + __m512i block_flags_vec = set1_512(block_flags); + __m512i msg_vecs[16]; + transpose_msg_vecs16(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); + + __m512i v[16] = { + h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], + h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], + set1_512(IV[0]), set1_512(IV[1]), set1_512(IV[2]), set1_512(IV[3]), + counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, + }; + round_fn16(v, msg_vecs, 0); + round_fn16(v, msg_vecs, 1); + round_fn16(v, msg_vecs, 2); + round_fn16(v, msg_vecs, 3); + round_fn16(v, msg_vecs, 4); + round_fn16(v, msg_vecs, 5); + round_fn16(v, msg_vecs, 6); + h_vecs[0] = xor_512(v[0], v[8]); + h_vecs[1] = xor_512(v[1], v[9]); + h_vecs[2] = xor_512(v[2], v[10]); + h_vecs[3] = xor_512(v[3], v[11]); + h_vecs[4] = xor_512(v[4], v[12]); + h_vecs[5] = xor_512(v[5], v[13]); + h_vecs[6] = xor_512(v[6], v[14]); + h_vecs[7] = xor_512(v[7], v[15]); + + block_flags = flags; + } + + // transpose_vecs_512 operates on a 16x16 matrix of words, but we only have 8 + // state vectors. Pad the matrix with zeros. After transposition, store the + // lower half of each vector. + __m512i padded[16] = { + h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], + h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], + set1_512(0), set1_512(0), set1_512(0), set1_512(0), + set1_512(0), set1_512(0), set1_512(0), set1_512(0), + }; + transpose_vecs_512(padded); + _mm256_mask_storeu_epi32(&out[0 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[0])); + _mm256_mask_storeu_epi32(&out[1 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[1])); + _mm256_mask_storeu_epi32(&out[2 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[2])); + _mm256_mask_storeu_epi32(&out[3 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[3])); + _mm256_mask_storeu_epi32(&out[4 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[4])); + _mm256_mask_storeu_epi32(&out[5 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[5])); + _mm256_mask_storeu_epi32(&out[6 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[6])); + _mm256_mask_storeu_epi32(&out[7 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[7])); + _mm256_mask_storeu_epi32(&out[8 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[8])); + _mm256_mask_storeu_epi32(&out[9 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[9])); + _mm256_mask_storeu_epi32(&out[10 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[10])); + _mm256_mask_storeu_epi32(&out[11 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[11])); + _mm256_mask_storeu_epi32(&out[12 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[12])); + _mm256_mask_storeu_epi32(&out[13 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[13])); + _mm256_mask_storeu_epi32(&out[14 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[14])); + _mm256_mask_storeu_epi32(&out[15 * sizeof(__m256i)], (__mmask8)-1, _mm512_castsi512_si256(padded[15])); +} + +/* + * ---------------------------------------------------------------------------- + * hash_many_avx512 + * ---------------------------------------------------------------------------- + */ + +INLINE void hash_one_avx512(const uint8_t *input, size_t blocks, + const uint32_t key[8], uint64_t counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { + uint32_t cv[8]; + memcpy(cv, key, BLAKE3_KEY_LEN); + uint8_t block_flags = flags | flags_start; + while (blocks > 0) { + if (blocks == 1) { + block_flags |= flags_end; + } + blake3_compress_in_place_avx512(cv, input, BLAKE3_BLOCK_LEN, counter, + block_flags); + input = &input[BLAKE3_BLOCK_LEN]; + blocks -= 1; + block_flags = flags; + } + memcpy(out, cv, BLAKE3_OUT_LEN); +} + +void blake3_hash_many_avx512(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out) { + while (num_inputs >= 16) { + blake3_hash16_avx512(inputs, blocks, key, counter, increment_counter, flags, + flags_start, flags_end, out); + if (increment_counter) { + counter += 16; + } + inputs += 16; + num_inputs -= 16; + out = &out[16 * BLAKE3_OUT_LEN]; + } + while (num_inputs >= 8) { + blake3_hash8_avx512(inputs, blocks, key, counter, increment_counter, flags, + flags_start, flags_end, out); + if (increment_counter) { + counter += 8; + } + inputs += 8; + num_inputs -= 8; + out = &out[8 * BLAKE3_OUT_LEN]; + } + while (num_inputs >= 4) { + blake3_hash4_avx512(inputs, blocks, key, counter, increment_counter, flags, + flags_start, flags_end, out); + if (increment_counter) { + counter += 4; + } + inputs += 4; + num_inputs -= 4; + out = &out[4 * BLAKE3_OUT_LEN]; + } + while (num_inputs > 0) { + hash_one_avx512(inputs[0], blocks, key, counter, flags, flags_start, + flags_end, out); + if (increment_counter) { + counter += 1; + } + inputs += 1; + num_inputs -= 1; + out = &out[BLAKE3_OUT_LEN]; + } +} diff --git a/src/Native/libmultihash/blake3/blake3_avx512_x86-64_unix.S b/src/Native/libmultihash/blake3/blake3_avx512_x86-64_unix.S new file mode 100644 index 000000000..fb28d2358 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx512_x86-64_unix.S @@ -0,0 +1,2581 @@ +#if defined(__ELF__) && defined(__CET__) && defined(__has_include) +#if __has_include() +#include +#endif +#endif + +#if !defined(_CET_ENDBR) +#define _CET_ENDBR +#endif + +.intel_syntax noprefix +.global _blake3_hash_many_avx512 +.global blake3_hash_many_avx512 +.global blake3_compress_in_place_avx512 +.global _blake3_compress_in_place_avx512 +.global blake3_compress_xof_avx512 +.global _blake3_compress_xof_avx512 + +#ifdef __APPLE__ +.text +#else +.section .text +#endif +.p2align 6 +_blake3_hash_many_avx512: +blake3_hash_many_avx512: + _CET_ENDBR + push r15 + push r14 + push r13 + push r12 + push rbx + push rbp + mov rbp, rsp + sub rsp, 144 + and rsp, 0xFFFFFFFFFFFFFFC0 + neg r9 + kmovw k1, r9d + vmovd xmm0, r8d + vpbroadcastd ymm0, xmm0 + shr r8, 32 + vmovd xmm1, r8d + vpbroadcastd ymm1, xmm1 + vmovdqa ymm4, ymm1 + vmovdqa ymm5, ymm1 + vpaddd ymm2, ymm0, ymmword ptr [ADD0+rip] + vpaddd ymm3, ymm0, ymmword ptr [ADD0+32+rip] + vpcmpltud k2, ymm2, ymm0 + vpcmpltud k3, ymm3, ymm0 + vpaddd ymm4 {k2}, ymm4, dword ptr [ADD1+rip] {1to8} + vpaddd ymm5 {k3}, ymm5, dword ptr [ADD1+rip] {1to8} + knotw k2, k1 + vmovdqa32 ymm2 {k2}, ymm0 + vmovdqa32 ymm3 {k2}, ymm0 + vmovdqa32 ymm4 {k2}, ymm1 + vmovdqa32 ymm5 {k2}, ymm1 + vmovdqa ymmword ptr [rsp], ymm2 + vmovdqa ymmword ptr [rsp+0x1*0x20], ymm3 + vmovdqa ymmword ptr [rsp+0x2*0x20], ymm4 + vmovdqa ymmword ptr [rsp+0x3*0x20], ymm5 + shl rdx, 6 + mov qword ptr [rsp+0x80], rdx + cmp rsi, 16 + jc 3f +2: + vpbroadcastd zmm0, dword ptr [rcx] + vpbroadcastd zmm1, dword ptr [rcx+0x1*0x4] + vpbroadcastd zmm2, dword ptr [rcx+0x2*0x4] + vpbroadcastd zmm3, dword ptr [rcx+0x3*0x4] + vpbroadcastd zmm4, dword ptr [rcx+0x4*0x4] + vpbroadcastd zmm5, dword ptr [rcx+0x5*0x4] + vpbroadcastd zmm6, dword ptr [rcx+0x6*0x4] + vpbroadcastd zmm7, dword ptr [rcx+0x7*0x4] + movzx eax, byte ptr [rbp+0x38] + movzx ebx, byte ptr [rbp+0x40] + or eax, ebx + xor edx, edx +.p2align 5 +9: + movzx ebx, byte ptr [rbp+0x48] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+0x80] + cmove eax, ebx + mov dword ptr [rsp+0x88], eax + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x40] + mov r13, qword ptr [rdi+0x48] + mov r14, qword ptr [rdi+0x50] + mov r15, qword ptr [rdi+0x58] + vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] + vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 + vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] + vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 + vpunpcklqdq zmm8, zmm16, zmm17 + vpunpckhqdq zmm9, zmm16, zmm17 + vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] + vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 + vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] + vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 + vpunpcklqdq zmm10, zmm18, zmm19 + vpunpckhqdq zmm11, zmm18, zmm19 + mov r8, qword ptr [rdi+0x20] + mov r9, qword ptr [rdi+0x28] + mov r10, qword ptr [rdi+0x30] + mov r11, qword ptr [rdi+0x38] + mov r12, qword ptr [rdi+0x60] + mov r13, qword ptr [rdi+0x68] + mov r14, qword ptr [rdi+0x70] + mov r15, qword ptr [rdi+0x78] + vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] + vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 + vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] + vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 + vpunpcklqdq zmm12, zmm16, zmm17 + vpunpckhqdq zmm13, zmm16, zmm17 + vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] + vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 + vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] + vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 + vpunpcklqdq zmm14, zmm18, zmm19 + vpunpckhqdq zmm15, zmm18, zmm19 + vmovdqa32 zmm27, zmmword ptr [INDEX0+rip] + vmovdqa32 zmm31, zmmword ptr [INDEX1+rip] + vshufps zmm16, zmm8, zmm10, 136 + vshufps zmm17, zmm12, zmm14, 136 + vmovdqa32 zmm20, zmm16 + vpermt2d zmm16, zmm27, zmm17 + vpermt2d zmm20, zmm31, zmm17 + vshufps zmm17, zmm8, zmm10, 221 + vshufps zmm30, zmm12, zmm14, 221 + vmovdqa32 zmm21, zmm17 + vpermt2d zmm17, zmm27, zmm30 + vpermt2d zmm21, zmm31, zmm30 + vshufps zmm18, zmm9, zmm11, 136 + vshufps zmm8, zmm13, zmm15, 136 + vmovdqa32 zmm22, zmm18 + vpermt2d zmm18, zmm27, zmm8 + vpermt2d zmm22, zmm31, zmm8 + vshufps zmm19, zmm9, zmm11, 221 + vshufps zmm8, zmm13, zmm15, 221 + vmovdqa32 zmm23, zmm19 + vpermt2d zmm19, zmm27, zmm8 + vpermt2d zmm23, zmm31, zmm8 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x40] + mov r13, qword ptr [rdi+0x48] + mov r14, qword ptr [rdi+0x50] + mov r15, qword ptr [rdi+0x58] + vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm8, zmm24, zmm25 + vpunpckhqdq zmm9, zmm24, zmm25 + vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm10, zmm24, zmm25 + vpunpckhqdq zmm11, zmm24, zmm25 + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r12+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r13+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r14+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + prefetcht0 [r15+rdx+0x80] + mov r8, qword ptr [rdi+0x20] + mov r9, qword ptr [rdi+0x28] + mov r10, qword ptr [rdi+0x30] + mov r11, qword ptr [rdi+0x38] + mov r12, qword ptr [rdi+0x60] + mov r13, qword ptr [rdi+0x68] + mov r14, qword ptr [rdi+0x70] + mov r15, qword ptr [rdi+0x78] + vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm12, zmm24, zmm25 + vpunpckhqdq zmm13, zmm24, zmm25 + vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm14, zmm24, zmm25 + vpunpckhqdq zmm15, zmm24, zmm25 + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r12+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r13+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r14+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + prefetcht0 [r15+rdx+0x80] + vshufps zmm24, zmm8, zmm10, 136 + vshufps zmm30, zmm12, zmm14, 136 + vmovdqa32 zmm28, zmm24 + vpermt2d zmm24, zmm27, zmm30 + vpermt2d zmm28, zmm31, zmm30 + vshufps zmm25, zmm8, zmm10, 221 + vshufps zmm30, zmm12, zmm14, 221 + vmovdqa32 zmm29, zmm25 + vpermt2d zmm25, zmm27, zmm30 + vpermt2d zmm29, zmm31, zmm30 + vshufps zmm26, zmm9, zmm11, 136 + vshufps zmm8, zmm13, zmm15, 136 + vmovdqa32 zmm30, zmm26 + vpermt2d zmm26, zmm27, zmm8 + vpermt2d zmm30, zmm31, zmm8 + vshufps zmm8, zmm9, zmm11, 221 + vshufps zmm10, zmm13, zmm15, 221 + vpermi2d zmm27, zmm8, zmm10 + vpermi2d zmm31, zmm8, zmm10 + vpbroadcastd zmm8, dword ptr [BLAKE3_IV_0+rip] + vpbroadcastd zmm9, dword ptr [BLAKE3_IV_1+rip] + vpbroadcastd zmm10, dword ptr [BLAKE3_IV_2+rip] + vpbroadcastd zmm11, dword ptr [BLAKE3_IV_3+rip] + vmovdqa32 zmm12, zmmword ptr [rsp] + vmovdqa32 zmm13, zmmword ptr [rsp+0x1*0x40] + vpbroadcastd zmm14, dword ptr [BLAKE3_BLOCK_LEN+rip] + vpbroadcastd zmm15, dword ptr [rsp+0x22*0x4] + vpaddd zmm0, zmm0, zmm16 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm20 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm17 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm21 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm24 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm28 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm25 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm29 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm18 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm23 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm22 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm16 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm17 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm25 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm27 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm30 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm19 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm29 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm20 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm18 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm22 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm27 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm21 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm31 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm26 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm30 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm23 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm19 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm20 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm21 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm16 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm24 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm28 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm31 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm29 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm26 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm23 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm16 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm18 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm17 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm25 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm24 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm30 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm28 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm29 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm18 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm19 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm22 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm27 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm17 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm31 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm25 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm30 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm19 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm26 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm20 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpxord zmm0, zmm0, zmm8 + vpxord zmm1, zmm1, zmm9 + vpxord zmm2, zmm2, zmm10 + vpxord zmm3, zmm3, zmm11 + vpxord zmm4, zmm4, zmm12 + vpxord zmm5, zmm5, zmm13 + vpxord zmm6, zmm6, zmm14 + vpxord zmm7, zmm7, zmm15 + movzx eax, byte ptr [rbp+0x38] + jne 9b + mov rbx, qword ptr [rbp+0x50] + vpunpckldq zmm16, zmm0, zmm1 + vpunpckhdq zmm17, zmm0, zmm1 + vpunpckldq zmm18, zmm2, zmm3 + vpunpckhdq zmm19, zmm2, zmm3 + vpunpckldq zmm20, zmm4, zmm5 + vpunpckhdq zmm21, zmm4, zmm5 + vpunpckldq zmm22, zmm6, zmm7 + vpunpckhdq zmm23, zmm6, zmm7 + vpunpcklqdq zmm0, zmm16, zmm18 + vpunpckhqdq zmm1, zmm16, zmm18 + vpunpcklqdq zmm2, zmm17, zmm19 + vpunpckhqdq zmm3, zmm17, zmm19 + vpunpcklqdq zmm4, zmm20, zmm22 + vpunpckhqdq zmm5, zmm20, zmm22 + vpunpcklqdq zmm6, zmm21, zmm23 + vpunpckhqdq zmm7, zmm21, zmm23 + vshufi32x4 zmm16, zmm0, zmm4, 0x88 + vshufi32x4 zmm17, zmm1, zmm5, 0x88 + vshufi32x4 zmm18, zmm2, zmm6, 0x88 + vshufi32x4 zmm19, zmm3, zmm7, 0x88 + vshufi32x4 zmm20, zmm0, zmm4, 0xDD + vshufi32x4 zmm21, zmm1, zmm5, 0xDD + vshufi32x4 zmm22, zmm2, zmm6, 0xDD + vshufi32x4 zmm23, zmm3, zmm7, 0xDD + vshufi32x4 zmm0, zmm16, zmm17, 0x88 + vshufi32x4 zmm1, zmm18, zmm19, 0x88 + vshufi32x4 zmm2, zmm20, zmm21, 0x88 + vshufi32x4 zmm3, zmm22, zmm23, 0x88 + vshufi32x4 zmm4, zmm16, zmm17, 0xDD + vshufi32x4 zmm5, zmm18, zmm19, 0xDD + vshufi32x4 zmm6, zmm20, zmm21, 0xDD + vshufi32x4 zmm7, zmm22, zmm23, 0xDD + vmovdqu32 zmmword ptr [rbx], zmm0 + vmovdqu32 zmmword ptr [rbx+0x1*0x40], zmm1 + vmovdqu32 zmmword ptr [rbx+0x2*0x40], zmm2 + vmovdqu32 zmmword ptr [rbx+0x3*0x40], zmm3 + vmovdqu32 zmmword ptr [rbx+0x4*0x40], zmm4 + vmovdqu32 zmmword ptr [rbx+0x5*0x40], zmm5 + vmovdqu32 zmmword ptr [rbx+0x6*0x40], zmm6 + vmovdqu32 zmmword ptr [rbx+0x7*0x40], zmm7 + vmovdqa32 zmm0, zmmword ptr [rsp] + vmovdqa32 zmm1, zmmword ptr [rsp+0x1*0x40] + vmovdqa32 zmm2, zmm0 + vpaddd zmm2{k1}, zmm0, dword ptr [ADD16+rip] {1to16} + vpcmpltud k2, zmm2, zmm0 + vpaddd zmm1 {k2}, zmm1, dword ptr [ADD1+rip] {1to16} + vmovdqa32 zmmword ptr [rsp], zmm2 + vmovdqa32 zmmword ptr [rsp+0x1*0x40], zmm1 + add rdi, 128 + add rbx, 512 + mov qword ptr [rbp+0x50], rbx + sub rsi, 16 + cmp rsi, 16 + jnc 2b + test rsi, rsi + jnz 3f +4: + vzeroupper + mov rsp, rbp + pop rbp + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + ret +.p2align 6 +3: + test esi, 0x8 + je 3f + vpbroadcastd ymm0, dword ptr [rcx] + vpbroadcastd ymm1, dword ptr [rcx+0x4] + vpbroadcastd ymm2, dword ptr [rcx+0x8] + vpbroadcastd ymm3, dword ptr [rcx+0xC] + vpbroadcastd ymm4, dword ptr [rcx+0x10] + vpbroadcastd ymm5, dword ptr [rcx+0x14] + vpbroadcastd ymm6, dword ptr [rcx+0x18] + vpbroadcastd ymm7, dword ptr [rcx+0x1C] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x20] + mov r13, qword ptr [rdi+0x28] + mov r14, qword ptr [rdi+0x30] + mov r15, qword ptr [rdi+0x38] + movzx eax, byte ptr [rbp+0x38] + movzx ebx, byte ptr [rbp+0x40] + or eax, ebx + xor edx, edx +2: + movzx ebx, byte ptr [rbp+0x48] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+0x80] + cmove eax, ebx + mov dword ptr [rsp+0x88], eax + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x40] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x40] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x40] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm16, ymm12, ymm14, 136 + vshufps ymm17, ymm12, ymm14, 221 + vshufps ymm18, ymm13, ymm15, 136 + vshufps ymm19, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x30] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x30] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x30] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm20, ymm12, ymm14, 136 + vshufps ymm21, ymm12, ymm14, 221 + vshufps ymm22, ymm13, ymm15, 136 + vshufps ymm23, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x20] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x20] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x20] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm24, ymm12, ymm14, 136 + vshufps ymm25, ymm12, ymm14, 221 + vshufps ymm26, ymm13, ymm15, 136 + vshufps ymm27, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x10] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x10] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x10] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm28, ymm12, ymm14, 136 + vshufps ymm29, ymm12, ymm14, 221 + vshufps ymm30, ymm13, ymm15, 136 + vshufps ymm31, ymm13, ymm15, 221 + vpbroadcastd ymm8, dword ptr [BLAKE3_IV_0+rip] + vpbroadcastd ymm9, dword ptr [BLAKE3_IV_1+rip] + vpbroadcastd ymm10, dword ptr [BLAKE3_IV_2+rip] + vpbroadcastd ymm11, dword ptr [BLAKE3_IV_3+rip] + vmovdqa ymm12, ymmword ptr [rsp] + vmovdqa ymm13, ymmword ptr [rsp+0x40] + vpbroadcastd ymm14, dword ptr [BLAKE3_BLOCK_LEN+rip] + vpbroadcastd ymm15, dword ptr [rsp+0x88] + vpaddd ymm0, ymm0, ymm16 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm20 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm17 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm21 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm24 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm28 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm25 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm29 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm18 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm23 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm22 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm16 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm17 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm25 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm27 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm30 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm19 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm29 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm20 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm18 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm22 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm27 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm21 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm31 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm26 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm30 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm23 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm19 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm20 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm21 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm16 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm24 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm28 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm31 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm29 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm26 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm23 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm16 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm18 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm17 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm25 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm24 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm30 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm28 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm29 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm18 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm19 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm22 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm27 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm17 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm31 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm25 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm30 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm19 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm26 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm20 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpxor ymm0, ymm0, ymm8 + vpxor ymm1, ymm1, ymm9 + vpxor ymm2, ymm2, ymm10 + vpxor ymm3, ymm3, ymm11 + vpxor ymm4, ymm4, ymm12 + vpxor ymm5, ymm5, ymm13 + vpxor ymm6, ymm6, ymm14 + vpxor ymm7, ymm7, ymm15 + movzx eax, byte ptr [rbp+0x38] + jne 2b + mov rbx, qword ptr [rbp+0x50] + vunpcklps ymm8, ymm0, ymm1 + vunpcklps ymm9, ymm2, ymm3 + vunpckhps ymm10, ymm0, ymm1 + vunpcklps ymm11, ymm4, ymm5 + vunpcklps ymm0, ymm6, ymm7 + vshufps ymm12, ymm8, ymm9, 78 + vblendps ymm1, ymm8, ymm12, 0xCC + vshufps ymm8, ymm11, ymm0, 78 + vunpckhps ymm13, ymm2, ymm3 + vblendps ymm2, ymm11, ymm8, 0xCC + vblendps ymm3, ymm12, ymm9, 0xCC + vperm2f128 ymm12, ymm1, ymm2, 0x20 + vmovups ymmword ptr [rbx], ymm12 + vunpckhps ymm14, ymm4, ymm5 + vblendps ymm4, ymm8, ymm0, 0xCC + vunpckhps ymm15, ymm6, ymm7 + vperm2f128 ymm7, ymm3, ymm4, 0x20 + vmovups ymmword ptr [rbx+0x20], ymm7 + vshufps ymm5, ymm10, ymm13, 78 + vblendps ymm6, ymm5, ymm13, 0xCC + vshufps ymm13, ymm14, ymm15, 78 + vblendps ymm10, ymm10, ymm5, 0xCC + vblendps ymm14, ymm14, ymm13, 0xCC + vperm2f128 ymm8, ymm10, ymm14, 0x20 + vmovups ymmword ptr [rbx+0x40], ymm8 + vblendps ymm15, ymm13, ymm15, 0xCC + vperm2f128 ymm13, ymm6, ymm15, 0x20 + vmovups ymmword ptr [rbx+0x60], ymm13 + vperm2f128 ymm9, ymm1, ymm2, 0x31 + vperm2f128 ymm11, ymm3, ymm4, 0x31 + vmovups ymmword ptr [rbx+0x80], ymm9 + vperm2f128 ymm14, ymm10, ymm14, 0x31 + vperm2f128 ymm15, ymm6, ymm15, 0x31 + vmovups ymmword ptr [rbx+0xA0], ymm11 + vmovups ymmword ptr [rbx+0xC0], ymm14 + vmovups ymmword ptr [rbx+0xE0], ymm15 + vmovdqa ymm0, ymmword ptr [rsp] + vmovdqa ymm2, ymmword ptr [rsp+0x2*0x20] + vmovdqa32 ymm0 {k1}, ymmword ptr [rsp+0x1*0x20] + vmovdqa32 ymm2 {k1}, ymmword ptr [rsp+0x3*0x20] + vmovdqa ymmword ptr [rsp], ymm0 + vmovdqa ymmword ptr [rsp+0x2*0x20], ymm2 + add rbx, 256 + mov qword ptr [rbp+0x50], rbx + add rdi, 64 + sub rsi, 8 +3: + mov rbx, qword ptr [rbp+0x50] + mov r15, qword ptr [rsp+0x80] + movzx r13, byte ptr [rbp+0x38] + movzx r12, byte ptr [rbp+0x48] + test esi, 0x4 + je 3f + vbroadcasti32x4 zmm0, xmmword ptr [rcx] + vbroadcasti32x4 zmm1, xmmword ptr [rcx+0x1*0x10] + vmovdqa xmm12, xmmword ptr [rsp] + vmovdqa xmm13, xmmword ptr [rsp+0x4*0x10] + vpunpckldq xmm14, xmm12, xmm13 + vpunpckhdq xmm15, xmm12, xmm13 + vpermq ymm14, ymm14, 0xDC + vpermq ymm15, ymm15, 0xDC + vpbroadcastd zmm12, dword ptr [BLAKE3_BLOCK_LEN+rip] + vinserti64x4 zmm13, zmm14, ymm15, 0x01 + mov eax, 17476 + kmovw k2, eax + vpblendmd zmm13 {k2}, zmm13, zmm12 + vbroadcasti32x4 zmm15, xmmword ptr [BLAKE3_IV+rip] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov eax, 43690 + kmovw k3, eax + mov eax, 34952 + kmovw k4, eax + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x88], eax + vmovdqa32 zmm2, zmm15 + vpbroadcastd zmm8, dword ptr [rsp+0x22*0x4] + vpblendmd zmm3 {k4}, zmm13, zmm8 + vmovups zmm8, zmmword ptr [r8+rdx-0x1*0x40] + vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x4*0x10], 0x01 + vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x4*0x10], 0x02 + vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x4*0x10], 0x03 + vmovups zmm9, zmmword ptr [r8+rdx-0x30] + vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x3*0x10], 0x01 + vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x3*0x10], 0x02 + vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x3*0x10], 0x03 + vshufps zmm4, zmm8, zmm9, 136 + vshufps zmm5, zmm8, zmm9, 221 + vmovups zmm8, zmmword ptr [r8+rdx-0x20] + vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x2*0x10], 0x01 + vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x2*0x10], 0x02 + vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x2*0x10], 0x03 + vmovups zmm9, zmmword ptr [r8+rdx-0x10] + vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x1*0x10], 0x01 + vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x1*0x10], 0x02 + vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x1*0x10], 0x03 + vshufps zmm6, zmm8, zmm9, 136 + vshufps zmm7, zmm8, zmm9, 221 + vpshufd zmm6, zmm6, 0x93 + vpshufd zmm7, zmm7, 0x93 + mov al, 7 +9: + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 16 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 12 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 8 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 7 + vpshufd zmm0, zmm0, 0x93 + vpshufd zmm3, zmm3, 0x4E + vpshufd zmm2, zmm2, 0x39 + vpaddd zmm0, zmm0, zmm6 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 16 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 12 + vpaddd zmm0, zmm0, zmm7 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 8 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 7 + vpshufd zmm0, zmm0, 0x39 + vpshufd zmm3, zmm3, 0x4E + vpshufd zmm2, zmm2, 0x93 + dec al + jz 9f + vshufps zmm8, zmm4, zmm5, 214 + vpshufd zmm9, zmm4, 0x0F + vpshufd zmm4, zmm8, 0x39 + vshufps zmm8, zmm6, zmm7, 250 + vpblendmd zmm9 {k3}, zmm9, zmm8 + vpunpcklqdq zmm8, zmm7, zmm5 + vpblendmd zmm8 {k4}, zmm8, zmm6 + vpshufd zmm8, zmm8, 0x78 + vpunpckhdq zmm5, zmm5, zmm7 + vpunpckldq zmm6, zmm6, zmm5 + vpshufd zmm7, zmm6, 0x1E + vmovdqa32 zmm5, zmm9 + vmovdqa32 zmm6, zmm8 + jmp 9b +9: + vpxord zmm0, zmm0, zmm2 + vpxord zmm1, zmm1, zmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vextracti32x4 xmmword ptr [rbx+0x4*0x10], zmm0, 0x02 + vextracti32x4 xmmword ptr [rbx+0x5*0x10], zmm1, 0x02 + vextracti32x4 xmmword ptr [rbx+0x6*0x10], zmm0, 0x03 + vextracti32x4 xmmword ptr [rbx+0x7*0x10], zmm1, 0x03 + vmovdqa xmm0, xmmword ptr [rsp] + vmovdqa xmm2, xmmword ptr [rsp+0x40] + vmovdqa32 xmm0 {k1}, xmmword ptr [rsp+0x1*0x10] + vmovdqa32 xmm2 {k1}, xmmword ptr [rsp+0x5*0x10] + vmovdqa xmmword ptr [rsp], xmm0 + vmovdqa xmmword ptr [rsp+0x40], xmm2 + add rbx, 128 + add rdi, 32 + sub rsi, 4 +3: + test esi, 0x2 + je 3f + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] + vmovd xmm13, dword ptr [rsp] + vpinsrd xmm13, xmm13, dword ptr [rsp+0x40], 1 + vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovd xmm14, dword ptr [rsp+0x4] + vpinsrd xmm14, xmm14, dword ptr [rsp+0x44], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vinserti128 ymm13, ymm13, xmm14, 0x01 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x88], eax + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] + vpbroadcastd ymm8, dword ptr [rsp+0x88] + vpblendd ymm3, ymm13, ymm8, 0x88 + vmovups ymm8, ymmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 + vshufps ymm4, ymm8, ymm9, 136 + vshufps ymm5, ymm8, ymm9, 221 + vmovups ymm8, ymmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 + vshufps ymm6, ymm8, ymm9, 136 + vshufps ymm7, ymm8, ymm9, 221 + vpshufd ymm6, ymm6, 0x93 + vpshufd ymm7, ymm7, 0x93 + mov al, 7 +9: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 16 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 12 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 8 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 7 + vpshufd ymm0, ymm0, 0x93 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x39 + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 16 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 12 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 8 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 7 + vpshufd ymm0, ymm0, 0x39 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x93 + dec al + jz 9f + vshufps ymm8, ymm4, ymm5, 214 + vpshufd ymm9, ymm4, 0x0F + vpshufd ymm4, ymm8, 0x39 + vshufps ymm8, ymm6, ymm7, 250 + vpblendd ymm9, ymm9, ymm8, 0xAA + vpunpcklqdq ymm8, ymm7, ymm5 + vpblendd ymm8, ymm8, ymm6, 0x88 + vpshufd ymm8, ymm8, 0x78 + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 0x1E + vmovdqa ymm5, ymm9 + vmovdqa ymm6, ymm8 + jmp 9b +9: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vmovdqa xmm0, xmmword ptr [rsp] + vmovdqa xmm2, xmmword ptr [rsp+0x4*0x10] + vmovdqu32 xmm0 {k1}, xmmword ptr [rsp+0x8] + vmovdqu32 xmm2 {k1}, xmmword ptr [rsp+0x48] + vmovdqa xmmword ptr [rsp], xmm0 + vmovdqa xmmword ptr [rsp+0x4*0x10], xmm2 + add rbx, 64 + add rdi, 16 + sub rsi, 2 +3: + test esi, 0x1 + je 4b + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+0x10] + vmovd xmm14, dword ptr [rsp] + vpinsrd xmm14, xmm14, dword ptr [rsp+0x40], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovdqa xmm15, xmmword ptr [BLAKE3_IV+rip] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + vpinsrd xmm3, xmm14, eax, 3 + vmovdqa xmm2, xmm15 + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vmovups xmm9, xmmword ptr [r8+rdx-0x30] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vmovups xmm9, xmmword ptr [r8+rdx-0x10] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + jmp 4b +.p2align 6 +_blake3_compress_in_place_avx512: +blake3_compress_in_place_avx512: + _CET_ENDBR + vmovdqu xmm0, xmmword ptr [rdi] + vmovdqu xmm1, xmmword ptr [rdi+0x10] + movzx eax, r8b + movzx edx, dl + shl rax, 32 + add rdx, rax + vmovq xmm3, rcx + vmovq xmm4, rdx + vpunpcklqdq xmm3, xmm3, xmm4 + vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] + vmovups xmm8, xmmword ptr [rsi] + vmovups xmm9, xmmword ptr [rsi+0x10] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [rsi+0x20] + vmovups xmm9, xmmword ptr [rsi+0x30] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + vmovdqu xmmword ptr [rdi], xmm0 + vmovdqu xmmword ptr [rdi+0x10], xmm1 + ret + +.p2align 6 +_blake3_compress_xof_avx512: +blake3_compress_xof_avx512: + _CET_ENDBR + vmovdqu xmm0, xmmword ptr [rdi] + vmovdqu xmm1, xmmword ptr [rdi+0x10] + movzx eax, r8b + movzx edx, dl + shl rax, 32 + add rdx, rax + vmovq xmm3, rcx + vmovq xmm4, rdx + vpunpcklqdq xmm3, xmm3, xmm4 + vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] + vmovups xmm8, xmmword ptr [rsi] + vmovups xmm9, xmmword ptr [rsi+0x10] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [rsi+0x20] + vmovups xmm9, xmmword ptr [rsi+0x30] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + vpxor xmm2, xmm2, [rdi] + vpxor xmm3, xmm3, [rdi+0x10] + vmovdqu xmmword ptr [r9], xmm0 + vmovdqu xmmword ptr [r9+0x10], xmm1 + vmovdqu xmmword ptr [r9+0x20], xmm2 + vmovdqu xmmword ptr [r9+0x30], xmm3 + ret + +#ifdef __APPLE__ +.static_data +#else +.section .rodata +#endif +.p2align 6 +INDEX0: + .long 0, 1, 2, 3, 16, 17, 18, 19 + .long 8, 9, 10, 11, 24, 25, 26, 27 +INDEX1: + .long 4, 5, 6, 7, 20, 21, 22, 23 + .long 12, 13, 14, 15, 28, 29, 30, 31 +ADD0: + .long 0, 1, 2, 3, 4, 5, 6, 7 + .long 8, 9, 10, 11, 12, 13, 14, 15 +ADD1: .long 1 + +ADD16: .long 16 +BLAKE3_BLOCK_LEN: + .long 64 +.p2align 6 +BLAKE3_IV: +BLAKE3_IV_0: + .long 0x6A09E667 +BLAKE3_IV_1: + .long 0xBB67AE85 +BLAKE3_IV_2: + .long 0x3C6EF372 +BLAKE3_IV_3: + .long 0xA54FF53A diff --git a/src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_gnu.S b/src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_gnu.S new file mode 100644 index 000000000..e10b9f36c --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_gnu.S @@ -0,0 +1,2615 @@ +.intel_syntax noprefix + +.global _blake3_hash_many_avx512 +.global blake3_hash_many_avx512 +.global blake3_compress_in_place_avx512 +.global _blake3_compress_in_place_avx512 +.global blake3_compress_xof_avx512 +.global _blake3_compress_xof_avx512 + +.section .text +.p2align 6 +_blake3_hash_many_avx512: +blake3_hash_many_avx512: + push r15 + push r14 + push r13 + push r12 + push rdi + push rsi + push rbx + push rbp + mov rbp, rsp + sub rsp, 304 + and rsp, 0xFFFFFFFFFFFFFFC0 + vmovdqa xmmword ptr [rsp+0x90], xmm6 + vmovdqa xmmword ptr [rsp+0xA0], xmm7 + vmovdqa xmmword ptr [rsp+0xB0], xmm8 + vmovdqa xmmword ptr [rsp+0xC0], xmm9 + vmovdqa xmmword ptr [rsp+0xD0], xmm10 + vmovdqa xmmword ptr [rsp+0xE0], xmm11 + vmovdqa xmmword ptr [rsp+0xF0], xmm12 + vmovdqa xmmword ptr [rsp+0x100], xmm13 + vmovdqa xmmword ptr [rsp+0x110], xmm14 + vmovdqa xmmword ptr [rsp+0x120], xmm15 + mov rdi, rcx + mov rsi, rdx + mov rdx, r8 + mov rcx, r9 + mov r8, qword ptr [rbp+0x68] + movzx r9, byte ptr [rbp+0x70] + neg r9 + kmovw k1, r9d + vmovd xmm0, r8d + vpbroadcastd ymm0, xmm0 + shr r8, 32 + vmovd xmm1, r8d + vpbroadcastd ymm1, xmm1 + vmovdqa ymm4, ymm1 + vmovdqa ymm5, ymm1 + vpaddd ymm2, ymm0, ymmword ptr [ADD0+rip] + vpaddd ymm3, ymm0, ymmword ptr [ADD0+32+rip] + vpcmpltud k2, ymm2, ymm0 + vpcmpltud k3, ymm3, ymm0 + vpaddd ymm4 {k2}, ymm4, dword ptr [ADD1+rip] {1to8} + vpaddd ymm5 {k3}, ymm5, dword ptr [ADD1+rip] {1to8} + knotw k2, k1 + vmovdqa32 ymm2 {k2}, ymm0 + vmovdqa32 ymm3 {k2}, ymm0 + vmovdqa32 ymm4 {k2}, ymm1 + vmovdqa32 ymm5 {k2}, ymm1 + vmovdqa ymmword ptr [rsp], ymm2 + vmovdqa ymmword ptr [rsp+0x20], ymm3 + vmovdqa ymmword ptr [rsp+0x40], ymm4 + vmovdqa ymmword ptr [rsp+0x60], ymm5 + shl rdx, 6 + mov qword ptr [rsp+0x80], rdx + cmp rsi, 16 + jc 3f +2: + vpbroadcastd zmm0, dword ptr [rcx] + vpbroadcastd zmm1, dword ptr [rcx+0x1*0x4] + vpbroadcastd zmm2, dword ptr [rcx+0x2*0x4] + vpbroadcastd zmm3, dword ptr [rcx+0x3*0x4] + vpbroadcastd zmm4, dword ptr [rcx+0x4*0x4] + vpbroadcastd zmm5, dword ptr [rcx+0x5*0x4] + vpbroadcastd zmm6, dword ptr [rcx+0x6*0x4] + vpbroadcastd zmm7, dword ptr [rcx+0x7*0x4] + movzx eax, byte ptr [rbp+0x78] + movzx ebx, byte ptr [rbp+0x80] + or eax, ebx + xor edx, edx +.p2align 5 +9: + movzx ebx, byte ptr [rbp+0x88] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+0x80] + cmove eax, ebx + mov dword ptr [rsp+0x88], eax + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x40] + mov r13, qword ptr [rdi+0x48] + mov r14, qword ptr [rdi+0x50] + mov r15, qword ptr [rdi+0x58] + vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] + vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 + vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] + vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 + vpunpcklqdq zmm8, zmm16, zmm17 + vpunpckhqdq zmm9, zmm16, zmm17 + vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] + vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 + vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] + vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 + vpunpcklqdq zmm10, zmm18, zmm19 + vpunpckhqdq zmm11, zmm18, zmm19 + mov r8, qword ptr [rdi+0x20] + mov r9, qword ptr [rdi+0x28] + mov r10, qword ptr [rdi+0x30] + mov r11, qword ptr [rdi+0x38] + mov r12, qword ptr [rdi+0x60] + mov r13, qword ptr [rdi+0x68] + mov r14, qword ptr [rdi+0x70] + mov r15, qword ptr [rdi+0x78] + vmovdqu32 ymm16, ymmword ptr [rdx+r8-0x2*0x20] + vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-0x2*0x20], 0x01 + vmovdqu32 ymm17, ymmword ptr [rdx+r9-0x2*0x20] + vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-0x2*0x20], 0x01 + vpunpcklqdq zmm12, zmm16, zmm17 + vpunpckhqdq zmm13, zmm16, zmm17 + vmovdqu32 ymm18, ymmword ptr [rdx+r10-0x2*0x20] + vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-0x2*0x20], 0x01 + vmovdqu32 ymm19, ymmword ptr [rdx+r11-0x2*0x20] + vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-0x2*0x20], 0x01 + vpunpcklqdq zmm14, zmm18, zmm19 + vpunpckhqdq zmm15, zmm18, zmm19 + vmovdqa32 zmm27, zmmword ptr [INDEX0+rip] + vmovdqa32 zmm31, zmmword ptr [INDEX1+rip] + vshufps zmm16, zmm8, zmm10, 136 + vshufps zmm17, zmm12, zmm14, 136 + vmovdqa32 zmm20, zmm16 + vpermt2d zmm16, zmm27, zmm17 + vpermt2d zmm20, zmm31, zmm17 + vshufps zmm17, zmm8, zmm10, 221 + vshufps zmm30, zmm12, zmm14, 221 + vmovdqa32 zmm21, zmm17 + vpermt2d zmm17, zmm27, zmm30 + vpermt2d zmm21, zmm31, zmm30 + vshufps zmm18, zmm9, zmm11, 136 + vshufps zmm8, zmm13, zmm15, 136 + vmovdqa32 zmm22, zmm18 + vpermt2d zmm18, zmm27, zmm8 + vpermt2d zmm22, zmm31, zmm8 + vshufps zmm19, zmm9, zmm11, 221 + vshufps zmm8, zmm13, zmm15, 221 + vmovdqa32 zmm23, zmm19 + vpermt2d zmm19, zmm27, zmm8 + vpermt2d zmm23, zmm31, zmm8 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x40] + mov r13, qword ptr [rdi+0x48] + mov r14, qword ptr [rdi+0x50] + mov r15, qword ptr [rdi+0x58] + vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm8, zmm24, zmm25 + vpunpckhqdq zmm9, zmm24, zmm25 + vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm10, zmm24, zmm25 + vpunpckhqdq zmm11, zmm24, zmm25 + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r12+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r13+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r14+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + prefetcht0 [r15+rdx+0x80] + mov r8, qword ptr [rdi+0x20] + mov r9, qword ptr [rdi+0x28] + mov r10, qword ptr [rdi+0x30] + mov r11, qword ptr [rdi+0x38] + mov r12, qword ptr [rdi+0x60] + mov r13, qword ptr [rdi+0x68] + mov r14, qword ptr [rdi+0x70] + mov r15, qword ptr [rdi+0x78] + vmovdqu32 ymm24, ymmword ptr [r8+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r9+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm12, zmm24, zmm25 + vpunpckhqdq zmm13, zmm24, zmm25 + vmovdqu32 ymm24, ymmword ptr [r10+rdx-0x1*0x20] + vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-0x1*0x20], 0x01 + vmovdqu32 ymm25, ymmword ptr [r11+rdx-0x1*0x20] + vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-0x1*0x20], 0x01 + vpunpcklqdq zmm14, zmm24, zmm25 + vpunpckhqdq zmm15, zmm24, zmm25 + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r12+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r13+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r14+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + prefetcht0 [r15+rdx+0x80] + vshufps zmm24, zmm8, zmm10, 136 + vshufps zmm30, zmm12, zmm14, 136 + vmovdqa32 zmm28, zmm24 + vpermt2d zmm24, zmm27, zmm30 + vpermt2d zmm28, zmm31, zmm30 + vshufps zmm25, zmm8, zmm10, 221 + vshufps zmm30, zmm12, zmm14, 221 + vmovdqa32 zmm29, zmm25 + vpermt2d zmm25, zmm27, zmm30 + vpermt2d zmm29, zmm31, zmm30 + vshufps zmm26, zmm9, zmm11, 136 + vshufps zmm8, zmm13, zmm15, 136 + vmovdqa32 zmm30, zmm26 + vpermt2d zmm26, zmm27, zmm8 + vpermt2d zmm30, zmm31, zmm8 + vshufps zmm8, zmm9, zmm11, 221 + vshufps zmm10, zmm13, zmm15, 221 + vpermi2d zmm27, zmm8, zmm10 + vpermi2d zmm31, zmm8, zmm10 + vpbroadcastd zmm8, dword ptr [BLAKE3_IV_0+rip] + vpbroadcastd zmm9, dword ptr [BLAKE3_IV_1+rip] + vpbroadcastd zmm10, dword ptr [BLAKE3_IV_2+rip] + vpbroadcastd zmm11, dword ptr [BLAKE3_IV_3+rip] + vmovdqa32 zmm12, zmmword ptr [rsp] + vmovdqa32 zmm13, zmmword ptr [rsp+0x1*0x40] + vpbroadcastd zmm14, dword ptr [BLAKE3_BLOCK_LEN+rip] + vpbroadcastd zmm15, dword ptr [rsp+0x22*0x4] + vpaddd zmm0, zmm0, zmm16 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm20 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm17 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm21 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm24 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm28 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm25 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm29 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm18 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm23 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm22 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm16 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm17 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm25 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm27 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm30 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm19 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm29 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm20 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm18 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm22 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm27 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm21 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm31 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm26 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm30 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm23 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm19 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm20 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm21 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm16 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm24 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm28 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm31 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm29 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm26 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm23 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm16 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm18 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm17 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm25 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm24 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm30 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm28 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm29 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm18 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm19 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm22 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm27 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm17 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm31 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm25 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm30 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm19 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm26 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm20 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpxord zmm0, zmm0, zmm8 + vpxord zmm1, zmm1, zmm9 + vpxord zmm2, zmm2, zmm10 + vpxord zmm3, zmm3, zmm11 + vpxord zmm4, zmm4, zmm12 + vpxord zmm5, zmm5, zmm13 + vpxord zmm6, zmm6, zmm14 + vpxord zmm7, zmm7, zmm15 + movzx eax, byte ptr [rbp+0x78] + jne 9b + mov rbx, qword ptr [rbp+0x90] + vpunpckldq zmm16, zmm0, zmm1 + vpunpckhdq zmm17, zmm0, zmm1 + vpunpckldq zmm18, zmm2, zmm3 + vpunpckhdq zmm19, zmm2, zmm3 + vpunpckldq zmm20, zmm4, zmm5 + vpunpckhdq zmm21, zmm4, zmm5 + vpunpckldq zmm22, zmm6, zmm7 + vpunpckhdq zmm23, zmm6, zmm7 + vpunpcklqdq zmm0, zmm16, zmm18 + vpunpckhqdq zmm1, zmm16, zmm18 + vpunpcklqdq zmm2, zmm17, zmm19 + vpunpckhqdq zmm3, zmm17, zmm19 + vpunpcklqdq zmm4, zmm20, zmm22 + vpunpckhqdq zmm5, zmm20, zmm22 + vpunpcklqdq zmm6, zmm21, zmm23 + vpunpckhqdq zmm7, zmm21, zmm23 + vshufi32x4 zmm16, zmm0, zmm4, 0x88 + vshufi32x4 zmm17, zmm1, zmm5, 0x88 + vshufi32x4 zmm18, zmm2, zmm6, 0x88 + vshufi32x4 zmm19, zmm3, zmm7, 0x88 + vshufi32x4 zmm20, zmm0, zmm4, 0xDD + vshufi32x4 zmm21, zmm1, zmm5, 0xDD + vshufi32x4 zmm22, zmm2, zmm6, 0xDD + vshufi32x4 zmm23, zmm3, zmm7, 0xDD + vshufi32x4 zmm0, zmm16, zmm17, 0x88 + vshufi32x4 zmm1, zmm18, zmm19, 0x88 + vshufi32x4 zmm2, zmm20, zmm21, 0x88 + vshufi32x4 zmm3, zmm22, zmm23, 0x88 + vshufi32x4 zmm4, zmm16, zmm17, 0xDD + vshufi32x4 zmm5, zmm18, zmm19, 0xDD + vshufi32x4 zmm6, zmm20, zmm21, 0xDD + vshufi32x4 zmm7, zmm22, zmm23, 0xDD + vmovdqu32 zmmword ptr [rbx], zmm0 + vmovdqu32 zmmword ptr [rbx+0x1*0x40], zmm1 + vmovdqu32 zmmword ptr [rbx+0x2*0x40], zmm2 + vmovdqu32 zmmword ptr [rbx+0x3*0x40], zmm3 + vmovdqu32 zmmword ptr [rbx+0x4*0x40], zmm4 + vmovdqu32 zmmword ptr [rbx+0x5*0x40], zmm5 + vmovdqu32 zmmword ptr [rbx+0x6*0x40], zmm6 + vmovdqu32 zmmword ptr [rbx+0x7*0x40], zmm7 + vmovdqa32 zmm0, zmmword ptr [rsp] + vmovdqa32 zmm1, zmmword ptr [rsp+0x1*0x40] + vmovdqa32 zmm2, zmm0 + vpaddd zmm2{k1}, zmm0, dword ptr [ADD16+rip] {1to16} + vpcmpltud k2, zmm2, zmm0 + vpaddd zmm1 {k2}, zmm1, dword ptr [ADD1+rip] {1to16} + vmovdqa32 zmmword ptr [rsp], zmm2 + vmovdqa32 zmmword ptr [rsp+0x1*0x40], zmm1 + add rdi, 128 + add rbx, 512 + mov qword ptr [rbp+0x90], rbx + sub rsi, 16 + cmp rsi, 16 + jnc 2b + test rsi, rsi + jne 3f +4: + vzeroupper + vmovdqa xmm6, xmmword ptr [rsp+0x90] + vmovdqa xmm7, xmmword ptr [rsp+0xA0] + vmovdqa xmm8, xmmword ptr [rsp+0xB0] + vmovdqa xmm9, xmmword ptr [rsp+0xC0] + vmovdqa xmm10, xmmword ptr [rsp+0xD0] + vmovdqa xmm11, xmmword ptr [rsp+0xE0] + vmovdqa xmm12, xmmword ptr [rsp+0xF0] + vmovdqa xmm13, xmmword ptr [rsp+0x100] + vmovdqa xmm14, xmmword ptr [rsp+0x110] + vmovdqa xmm15, xmmword ptr [rsp+0x120] + mov rsp, rbp + pop rbp + pop rbx + pop rsi + pop rdi + pop r12 + pop r13 + pop r14 + pop r15 + ret +.p2align 6 +3: + test esi, 0x8 + je 3f + vpbroadcastd ymm0, dword ptr [rcx] + vpbroadcastd ymm1, dword ptr [rcx+0x4] + vpbroadcastd ymm2, dword ptr [rcx+0x8] + vpbroadcastd ymm3, dword ptr [rcx+0xC] + vpbroadcastd ymm4, dword ptr [rcx+0x10] + vpbroadcastd ymm5, dword ptr [rcx+0x14] + vpbroadcastd ymm6, dword ptr [rcx+0x18] + vpbroadcastd ymm7, dword ptr [rcx+0x1C] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov r12, qword ptr [rdi+0x20] + mov r13, qword ptr [rdi+0x28] + mov r14, qword ptr [rdi+0x30] + mov r15, qword ptr [rdi+0x38] + movzx eax, byte ptr [rbp+0x78] + movzx ebx, byte ptr [rbp+0x80] + or eax, ebx + xor edx, edx +2: + movzx ebx, byte ptr [rbp+0x88] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+0x80] + cmove eax, ebx + mov dword ptr [rsp+0x88], eax + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x40], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x40] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x40], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x40] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x40], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x40] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x40], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm16, ymm12, ymm14, 136 + vshufps ymm17, ymm12, ymm14, 221 + vshufps ymm18, ymm13, ymm15, 136 + vshufps ymm19, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x30] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x30], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x30], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x30] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x30], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x30] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x30], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm20, ymm12, ymm14, 136 + vshufps ymm21, ymm12, ymm14, 221 + vshufps ymm22, ymm13, ymm15, 136 + vshufps ymm23, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x20], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x20] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x20], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x20] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x20], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x20] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x20], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm24, ymm12, ymm14, 136 + vshufps ymm25, ymm12, ymm14, 221 + vshufps ymm26, ymm13, ymm15, 136 + vshufps ymm27, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x10] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-0x10], 0x01 + vmovups xmm9, xmmword ptr [r9+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-0x10], 0x01 + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-0x10] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-0x10], 0x01 + vmovups xmm11, xmmword ptr [r11+rdx-0x10] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-0x10], 0x01 + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm28, ymm12, ymm14, 136 + vshufps ymm29, ymm12, ymm14, 221 + vshufps ymm30, ymm13, ymm15, 136 + vshufps ymm31, ymm13, ymm15, 221 + vpbroadcastd ymm8, dword ptr [BLAKE3_IV_0+rip] + vpbroadcastd ymm9, dword ptr [BLAKE3_IV_1+rip] + vpbroadcastd ymm10, dword ptr [BLAKE3_IV_2+rip] + vpbroadcastd ymm11, dword ptr [BLAKE3_IV_3+rip] + vmovdqa ymm12, ymmword ptr [rsp] + vmovdqa ymm13, ymmword ptr [rsp+0x40] + vpbroadcastd ymm14, dword ptr [BLAKE3_BLOCK_LEN+rip] + vpbroadcastd ymm15, dword ptr [rsp+0x88] + vpaddd ymm0, ymm0, ymm16 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm20 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm17 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm21 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm24 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm28 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm25 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm29 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm18 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm23 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm22 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm16 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm17 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm25 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm27 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm30 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm19 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm29 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm20 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm18 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm22 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm27 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm21 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm31 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm26 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm30 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm23 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm19 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm20 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm21 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm16 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm24 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm28 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm31 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm29 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm26 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm23 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm16 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm18 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm17 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm25 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm24 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm30 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm28 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm29 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm18 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm19 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm22 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm27 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm17 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm31 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm25 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm30 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm19 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm26 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm20 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpxor ymm0, ymm0, ymm8 + vpxor ymm1, ymm1, ymm9 + vpxor ymm2, ymm2, ymm10 + vpxor ymm3, ymm3, ymm11 + vpxor ymm4, ymm4, ymm12 + vpxor ymm5, ymm5, ymm13 + vpxor ymm6, ymm6, ymm14 + vpxor ymm7, ymm7, ymm15 + movzx eax, byte ptr [rbp+0x78] + jne 2b + mov rbx, qword ptr [rbp+0x90] + vunpcklps ymm8, ymm0, ymm1 + vunpcklps ymm9, ymm2, ymm3 + vunpckhps ymm10, ymm0, ymm1 + vunpcklps ymm11, ymm4, ymm5 + vunpcklps ymm0, ymm6, ymm7 + vshufps ymm12, ymm8, ymm9, 78 + vblendps ymm1, ymm8, ymm12, 0xCC + vshufps ymm8, ymm11, ymm0, 78 + vunpckhps ymm13, ymm2, ymm3 + vblendps ymm2, ymm11, ymm8, 0xCC + vblendps ymm3, ymm12, ymm9, 0xCC + vperm2f128 ymm12, ymm1, ymm2, 0x20 + vmovups ymmword ptr [rbx], ymm12 + vunpckhps ymm14, ymm4, ymm5 + vblendps ymm4, ymm8, ymm0, 0xCC + vunpckhps ymm15, ymm6, ymm7 + vperm2f128 ymm7, ymm3, ymm4, 0x20 + vmovups ymmword ptr [rbx+0x20], ymm7 + vshufps ymm5, ymm10, ymm13, 78 + vblendps ymm6, ymm5, ymm13, 0xCC + vshufps ymm13, ymm14, ymm15, 78 + vblendps ymm10, ymm10, ymm5, 0xCC + vblendps ymm14, ymm14, ymm13, 0xCC + vperm2f128 ymm8, ymm10, ymm14, 0x20 + vmovups ymmword ptr [rbx+0x40], ymm8 + vblendps ymm15, ymm13, ymm15, 0xCC + vperm2f128 ymm13, ymm6, ymm15, 0x20 + vmovups ymmword ptr [rbx+0x60], ymm13 + vperm2f128 ymm9, ymm1, ymm2, 0x31 + vperm2f128 ymm11, ymm3, ymm4, 0x31 + vmovups ymmword ptr [rbx+0x80], ymm9 + vperm2f128 ymm14, ymm10, ymm14, 0x31 + vperm2f128 ymm15, ymm6, ymm15, 0x31 + vmovups ymmword ptr [rbx+0xA0], ymm11 + vmovups ymmword ptr [rbx+0xC0], ymm14 + vmovups ymmword ptr [rbx+0xE0], ymm15 + vmovdqa ymm0, ymmword ptr [rsp] + vmovdqa ymm2, ymmword ptr [rsp+0x40] + vmovdqa32 ymm0 {k1}, ymmword ptr [rsp+0x1*0x20] + vmovdqa32 ymm2 {k1}, ymmword ptr [rsp+0x3*0x20] + vmovdqa ymmword ptr [rsp], ymm0 + vmovdqa ymmword ptr [rsp+0x40], ymm2 + add rbx, 256 + mov qword ptr [rbp+0x90], rbx + add rdi, 64 + sub rsi, 8 +3: + mov rbx, qword ptr [rbp+0x90] + mov r15, qword ptr [rsp+0x80] + movzx r13, byte ptr [rbp+0x78] + movzx r12, byte ptr [rbp+0x88] + test esi, 0x4 + je 3f + vbroadcasti32x4 zmm0, xmmword ptr [rcx] + vbroadcasti32x4 zmm1, xmmword ptr [rcx+0x1*0x10] + vmovdqa xmm12, xmmword ptr [rsp] + vmovdqa xmm13, xmmword ptr [rsp+0x40] + vpunpckldq xmm14, xmm12, xmm13 + vpunpckhdq xmm15, xmm12, xmm13 + vpermq ymm14, ymm14, 0xDC + vpermq ymm15, ymm15, 0xDC + vpbroadcastd zmm12, dword ptr [BLAKE3_BLOCK_LEN+rip] + vinserti64x4 zmm13, zmm14, ymm15, 0x01 + mov eax, 17476 + kmovw k2, eax + vpblendmd zmm13 {k2}, zmm13, zmm12 + vbroadcasti32x4 zmm15, xmmword ptr [BLAKE3_IV+rip] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + mov eax, 43690 + kmovw k3, eax + mov eax, 34952 + kmovw k4, eax + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x88], eax + vmovdqa32 zmm2, zmm15 + vpbroadcastd zmm8, dword ptr [rsp+0x22*0x4] + vpblendmd zmm3 {k4}, zmm13, zmm8 + vmovups zmm8, zmmword ptr [r8+rdx-0x1*0x40] + vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x4*0x10], 0x01 + vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x4*0x10], 0x02 + vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x4*0x10], 0x03 + vmovups zmm9, zmmword ptr [r8+rdx-0x30] + vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x3*0x10], 0x01 + vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x3*0x10], 0x02 + vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x3*0x10], 0x03 + vshufps zmm4, zmm8, zmm9, 136 + vshufps zmm5, zmm8, zmm9, 221 + vmovups zmm8, zmmword ptr [r8+rdx-0x20] + vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-0x2*0x10], 0x01 + vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-0x2*0x10], 0x02 + vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-0x2*0x10], 0x03 + vmovups zmm9, zmmword ptr [r8+rdx-0x10] + vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-0x1*0x10], 0x01 + vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-0x1*0x10], 0x02 + vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-0x1*0x10], 0x03 + vshufps zmm6, zmm8, zmm9, 136 + vshufps zmm7, zmm8, zmm9, 221 + vpshufd zmm6, zmm6, 0x93 + vpshufd zmm7, zmm7, 0x93 + mov al, 7 +9: + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 16 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 12 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 8 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 7 + vpshufd zmm0, zmm0, 0x93 + vpshufd zmm3, zmm3, 0x4E + vpshufd zmm2, zmm2, 0x39 + vpaddd zmm0, zmm0, zmm6 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 16 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 12 + vpaddd zmm0, zmm0, zmm7 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 8 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 7 + vpshufd zmm0, zmm0, 0x39 + vpshufd zmm3, zmm3, 0x4E + vpshufd zmm2, zmm2, 0x93 + dec al + jz 9f + vshufps zmm8, zmm4, zmm5, 214 + vpshufd zmm9, zmm4, 0x0F + vpshufd zmm4, zmm8, 0x39 + vshufps zmm8, zmm6, zmm7, 250 + vpblendmd zmm9 {k3}, zmm9, zmm8 + vpunpcklqdq zmm8, zmm7, zmm5 + vpblendmd zmm8 {k4}, zmm8, zmm6 + vpshufd zmm8, zmm8, 0x78 + vpunpckhdq zmm5, zmm5, zmm7 + vpunpckldq zmm6, zmm6, zmm5 + vpshufd zmm7, zmm6, 0x1E + vmovdqa32 zmm5, zmm9 + vmovdqa32 zmm6, zmm8 + jmp 9b +9: + vpxord zmm0, zmm0, zmm2 + vpxord zmm1, zmm1, zmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vextracti32x4 xmmword ptr [rbx+0x4*0x10], zmm0, 0x02 + vextracti32x4 xmmword ptr [rbx+0x5*0x10], zmm1, 0x02 + vextracti32x4 xmmword ptr [rbx+0x6*0x10], zmm0, 0x03 + vextracti32x4 xmmword ptr [rbx+0x7*0x10], zmm1, 0x03 + vmovdqa xmm0, xmmword ptr [rsp] + vmovdqa xmm2, xmmword ptr [rsp+0x40] + vmovdqa32 xmm0 {k1}, xmmword ptr [rsp+0x1*0x10] + vmovdqa32 xmm2 {k1}, xmmword ptr [rsp+0x5*0x10] + vmovdqa xmmword ptr [rsp], xmm0 + vmovdqa xmmword ptr [rsp+0x40], xmm2 + add rbx, 128 + add rdi, 32 + sub rsi, 4 +3: + test esi, 0x2 + je 3f + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+0x10] + vmovd xmm13, dword ptr [rsp] + vpinsrd xmm13, xmm13, dword ptr [rsp+0x40], 1 + vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovd xmm14, dword ptr [rsp+0x4] + vpinsrd xmm14, xmm14, dword ptr [rsp+0x44], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vinserti128 ymm13, ymm13, xmm14, 0x01 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+0x88], eax + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV+rip] + vpbroadcastd ymm8, dword ptr [rsp+0x88] + vpblendd ymm3, ymm13, ymm8, 0x88 + vmovups ymm8, ymmword ptr [r8+rdx-0x40] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x40], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x30] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x30], 0x01 + vshufps ymm4, ymm8, ymm9, 136 + vshufps ymm5, ymm8, ymm9, 221 + vmovups ymm8, ymmword ptr [r8+rdx-0x20] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-0x20], 0x01 + vmovups ymm9, ymmword ptr [r8+rdx-0x10] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-0x10], 0x01 + vshufps ymm6, ymm8, ymm9, 136 + vshufps ymm7, ymm8, ymm9, 221 + vpshufd ymm6, ymm6, 0x93 + vpshufd ymm7, ymm7, 0x93 + mov al, 7 +9: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 16 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 12 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 8 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 7 + vpshufd ymm0, ymm0, 0x93 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x39 + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 16 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 12 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 8 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 7 + vpshufd ymm0, ymm0, 0x39 + vpshufd ymm3, ymm3, 0x4E + vpshufd ymm2, ymm2, 0x93 + dec al + jz 9f + vshufps ymm8, ymm4, ymm5, 214 + vpshufd ymm9, ymm4, 0x0F + vpshufd ymm4, ymm8, 0x39 + vshufps ymm8, ymm6, ymm7, 250 + vpblendd ymm9, ymm9, ymm8, 0xAA + vpunpcklqdq ymm8, ymm7, ymm5 + vpblendd ymm8, ymm8, ymm6, 0x88 + vpshufd ymm8, ymm8, 0x78 + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 0x1E + vmovdqa ymm5, ymm9 + vmovdqa ymm6, ymm8 + jmp 9b +9: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + vextracti128 xmmword ptr [rbx+0x20], ymm0, 0x01 + vextracti128 xmmword ptr [rbx+0x30], ymm1, 0x01 + vmovdqa xmm0, xmmword ptr [rsp] + vmovdqa xmm2, xmmword ptr [rsp+0x40] + vmovdqu32 xmm0 {k1}, xmmword ptr [rsp+0x8] + vmovdqu32 xmm2 {k1}, xmmword ptr [rsp+0x48] + vmovdqa xmmword ptr [rsp], xmm0 + vmovdqa xmmword ptr [rsp+0x40], xmm2 + add rbx, 64 + add rdi, 16 + sub rsi, 2 +3: + test esi, 0x1 + je 4b + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+0x10] + vmovd xmm14, dword ptr [rsp] + vpinsrd xmm14, xmm14, dword ptr [rsp+0x40], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + vmovdqa xmm15, xmmword ptr [BLAKE3_IV+rip] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +.p2align 5 +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + vpinsrd xmm3, xmm14, eax, 3 + vmovdqa xmm2, xmm15 + vmovups xmm8, xmmword ptr [r8+rdx-0x40] + vmovups xmm9, xmmword ptr [r8+rdx-0x30] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [r8+rdx-0x20] + vmovups xmm9, xmmword ptr [r8+rdx-0x10] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+0x10], xmm1 + jmp 4b + + +.p2align 6 +_blake3_compress_in_place_avx512: +blake3_compress_in_place_avx512: + sub rsp, 72 + vmovdqa xmmword ptr [rsp], xmm6 + vmovdqa xmmword ptr [rsp+0x10], xmm7 + vmovdqa xmmword ptr [rsp+0x20], xmm8 + vmovdqa xmmword ptr [rsp+0x30], xmm9 + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+0x10] + movzx eax, byte ptr [rsp+0x70] + movzx r8d, r8b + shl rax, 32 + add r8, rax + vmovq xmm3, r9 + vmovq xmm4, r8 + vpunpcklqdq xmm3, xmm3, xmm4 + vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] + vmovups xmm8, xmmword ptr [rdx] + vmovups xmm9, xmmword ptr [rdx+0x10] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [rdx+0x20] + vmovups xmm9, xmmword ptr [rdx+0x30] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + vmovdqu xmmword ptr [rcx], xmm0 + vmovdqu xmmword ptr [rcx+0x10], xmm1 + vmovdqa xmm6, xmmword ptr [rsp] + vmovdqa xmm7, xmmword ptr [rsp+0x10] + vmovdqa xmm8, xmmword ptr [rsp+0x20] + vmovdqa xmm9, xmmword ptr [rsp+0x30] + add rsp, 72 + ret + + +.p2align 6 +_blake3_compress_xof_avx512: +blake3_compress_xof_avx512: + sub rsp, 72 + vmovdqa xmmword ptr [rsp], xmm6 + vmovdqa xmmword ptr [rsp+0x10], xmm7 + vmovdqa xmmword ptr [rsp+0x20], xmm8 + vmovdqa xmmword ptr [rsp+0x30], xmm9 + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+0x10] + movzx eax, byte ptr [rsp+0x70] + movzx r8d, r8b + mov r10, qword ptr [rsp+0x78] + shl rax, 32 + add r8, rax + vmovq xmm3, r9 + vmovq xmm4, r8 + vpunpcklqdq xmm3, xmm3, xmm4 + vmovaps xmm2, xmmword ptr [BLAKE3_IV+rip] + vmovups xmm8, xmmword ptr [rdx] + vmovups xmm9, xmmword ptr [rdx+0x10] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [rdx+0x20] + vmovups xmm9, xmmword ptr [rdx+0x30] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 0x93 + vpshufd xmm7, xmm7, 0x93 + mov al, 7 +9: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x93 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x39 + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 0x39 + vpshufd xmm3, xmm3, 0x4E + vpshufd xmm2, xmm2, 0x93 + dec al + jz 9f + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0x0F + vpshufd xmm4, xmm8, 0x39 + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0xAA + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 0x88 + vpshufd xmm8, xmm8, 0x78 + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 0x1E + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp 9b +9: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + vpxor xmm2, xmm2, xmmword ptr [rcx] + vpxor xmm3, xmm3, xmmword ptr [rcx+0x10] + vmovdqu xmmword ptr [r10], xmm0 + vmovdqu xmmword ptr [r10+0x10], xmm1 + vmovdqu xmmword ptr [r10+0x20], xmm2 + vmovdqu xmmword ptr [r10+0x30], xmm3 + vmovdqa xmm6, xmmword ptr [rsp] + vmovdqa xmm7, xmmword ptr [rsp+0x10] + vmovdqa xmm8, xmmword ptr [rsp+0x20] + vmovdqa xmm9, xmmword ptr [rsp+0x30] + add rsp, 72 + ret + +.section .rodata +.p2align 6 +INDEX0: + .long 0, 1, 2, 3, 16, 17, 18, 19 + .long 8, 9, 10, 11, 24, 25, 26, 27 +INDEX1: + .long 4, 5, 6, 7, 20, 21, 22, 23 + .long 12, 13, 14, 15, 28, 29, 30, 31 +ADD0: + .long 0, 1, 2, 3, 4, 5, 6, 7 + .long 8, 9, 10, 11, 12, 13, 14, 15 +ADD1: .long 1 + +ADD16: .long 16 +BLAKE3_BLOCK_LEN: + .long 64 +.p2align 6 +BLAKE3_IV: +BLAKE3_IV_0: + .long 0x6A09E667 +BLAKE3_IV_1: + .long 0xBB67AE85 +BLAKE3_IV_2: + .long 0x3C6EF372 +BLAKE3_IV_3: + .long 0xA54FF53A diff --git a/src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_msvc.asm b/src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_msvc.asm new file mode 100644 index 000000000..b19efbaae --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_avx512_x86-64_windows_msvc.asm @@ -0,0 +1,2634 @@ +public _blake3_hash_many_avx512 +public blake3_hash_many_avx512 +public blake3_compress_in_place_avx512 +public _blake3_compress_in_place_avx512 +public blake3_compress_xof_avx512 +public _blake3_compress_xof_avx512 + +_TEXT SEGMENT ALIGN(16) 'CODE' + +ALIGN 16 +blake3_hash_many_avx512 PROC +_blake3_hash_many_avx512 PROC + push r15 + push r14 + push r13 + push r12 + push rdi + push rsi + push rbx + push rbp + mov rbp, rsp + sub rsp, 304 + and rsp, 0FFFFFFFFFFFFFFC0H + vmovdqa xmmword ptr [rsp+90H], xmm6 + vmovdqa xmmword ptr [rsp+0A0H], xmm7 + vmovdqa xmmword ptr [rsp+0B0H], xmm8 + vmovdqa xmmword ptr [rsp+0C0H], xmm9 + vmovdqa xmmword ptr [rsp+0D0H], xmm10 + vmovdqa xmmword ptr [rsp+0E0H], xmm11 + vmovdqa xmmword ptr [rsp+0F0H], xmm12 + vmovdqa xmmword ptr [rsp+100H], xmm13 + vmovdqa xmmword ptr [rsp+110H], xmm14 + vmovdqa xmmword ptr [rsp+120H], xmm15 + mov rdi, rcx + mov rsi, rdx + mov rdx, r8 + mov rcx, r9 + mov r8, qword ptr [rbp+68H] + movzx r9, byte ptr [rbp+70H] + neg r9 + kmovw k1, r9d + vmovd xmm0, r8d + vpbroadcastd ymm0, xmm0 + shr r8, 32 + vmovd xmm1, r8d + vpbroadcastd ymm1, xmm1 + vmovdqa ymm4, ymm1 + vmovdqa ymm5, ymm1 + vpaddd ymm2, ymm0, ymmword ptr [ADD0] + vpaddd ymm3, ymm0, ymmword ptr [ADD0+32] + vpcmpud k2, ymm2, ymm0, 1 + vpcmpud k3, ymm3, ymm0, 1 + ; XXX: ml64.exe does not currently understand the syntax. We use a workaround. + vpbroadcastd ymm6, dword ptr [ADD1] + vpaddd ymm4 {k2}, ymm4, ymm6 + vpaddd ymm5 {k3}, ymm5, ymm6 + ; vpaddd ymm4 {k2}, ymm4, dword ptr [ADD1] {1to8} + ; vpaddd ymm5 {k3}, ymm5, dword ptr [ADD1] {1to8} + knotw k2, k1 + vmovdqa32 ymm2 {k2}, ymm0 + vmovdqa32 ymm3 {k2}, ymm0 + vmovdqa32 ymm4 {k2}, ymm1 + vmovdqa32 ymm5 {k2}, ymm1 + vmovdqa ymmword ptr [rsp], ymm2 + vmovdqa ymmword ptr [rsp+20H], ymm3 + vmovdqa ymmword ptr [rsp+40H], ymm4 + vmovdqa ymmword ptr [rsp+60H], ymm5 + shl rdx, 6 + mov qword ptr [rsp+80H], rdx + cmp rsi, 16 + jc final15blocks +outerloop16: + vpbroadcastd zmm0, dword ptr [rcx] + vpbroadcastd zmm1, dword ptr [rcx+1H*4H] + vpbroadcastd zmm2, dword ptr [rcx+2H*4H] + vpbroadcastd zmm3, dword ptr [rcx+3H*4H] + vpbroadcastd zmm4, dword ptr [rcx+4H*4H] + vpbroadcastd zmm5, dword ptr [rcx+5H*4H] + vpbroadcastd zmm6, dword ptr [rcx+6H*4H] + vpbroadcastd zmm7, dword ptr [rcx+7H*4H] + movzx eax, byte ptr [rbp+78H] + movzx ebx, byte ptr [rbp+80H] + or eax, ebx + xor edx, edx +ALIGN 16 +innerloop16: + movzx ebx, byte ptr [rbp+88H] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+80H] + cmove eax, ebx + mov dword ptr [rsp+88H], eax + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + mov r10, qword ptr [rdi+10H] + mov r11, qword ptr [rdi+18H] + mov r12, qword ptr [rdi+40H] + mov r13, qword ptr [rdi+48H] + mov r14, qword ptr [rdi+50H] + mov r15, qword ptr [rdi+58H] + vmovdqu32 ymm16, ymmword ptr [rdx+r8-2H*20H] + vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-2H*20H], 01H + vmovdqu32 ymm17, ymmword ptr [rdx+r9-2H*20H] + vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-2H*20H], 01H + vpunpcklqdq zmm8, zmm16, zmm17 + vpunpckhqdq zmm9, zmm16, zmm17 + vmovdqu32 ymm18, ymmword ptr [rdx+r10-2H*20H] + vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-2H*20H], 01H + vmovdqu32 ymm19, ymmword ptr [rdx+r11-2H*20H] + vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-2H*20H], 01H + vpunpcklqdq zmm10, zmm18, zmm19 + vpunpckhqdq zmm11, zmm18, zmm19 + mov r8, qword ptr [rdi+20H] + mov r9, qword ptr [rdi+28H] + mov r10, qword ptr [rdi+30H] + mov r11, qword ptr [rdi+38H] + mov r12, qword ptr [rdi+60H] + mov r13, qword ptr [rdi+68H] + mov r14, qword ptr [rdi+70H] + mov r15, qword ptr [rdi+78H] + vmovdqu32 ymm16, ymmword ptr [rdx+r8-2H*20H] + vinserti64x4 zmm16, zmm16, ymmword ptr [rdx+r12-2H*20H], 01H + vmovdqu32 ymm17, ymmword ptr [rdx+r9-2H*20H] + vinserti64x4 zmm17, zmm17, ymmword ptr [rdx+r13-2H*20H], 01H + vpunpcklqdq zmm12, zmm16, zmm17 + vpunpckhqdq zmm13, zmm16, zmm17 + vmovdqu32 ymm18, ymmword ptr [rdx+r10-2H*20H] + vinserti64x4 zmm18, zmm18, ymmword ptr [rdx+r14-2H*20H], 01H + vmovdqu32 ymm19, ymmword ptr [rdx+r11-2H*20H] + vinserti64x4 zmm19, zmm19, ymmword ptr [rdx+r15-2H*20H], 01H + vpunpcklqdq zmm14, zmm18, zmm19 + vpunpckhqdq zmm15, zmm18, zmm19 + vmovdqa32 zmm27, zmmword ptr [INDEX0] + vmovdqa32 zmm31, zmmword ptr [INDEX1] + vshufps zmm16, zmm8, zmm10, 136 + vshufps zmm17, zmm12, zmm14, 136 + vmovdqa32 zmm20, zmm16 + vpermt2d zmm16, zmm27, zmm17 + vpermt2d zmm20, zmm31, zmm17 + vshufps zmm17, zmm8, zmm10, 221 + vshufps zmm30, zmm12, zmm14, 221 + vmovdqa32 zmm21, zmm17 + vpermt2d zmm17, zmm27, zmm30 + vpermt2d zmm21, zmm31, zmm30 + vshufps zmm18, zmm9, zmm11, 136 + vshufps zmm8, zmm13, zmm15, 136 + vmovdqa32 zmm22, zmm18 + vpermt2d zmm18, zmm27, zmm8 + vpermt2d zmm22, zmm31, zmm8 + vshufps zmm19, zmm9, zmm11, 221 + vshufps zmm8, zmm13, zmm15, 221 + vmovdqa32 zmm23, zmm19 + vpermt2d zmm19, zmm27, zmm8 + vpermt2d zmm23, zmm31, zmm8 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + mov r10, qword ptr [rdi+10H] + mov r11, qword ptr [rdi+18H] + mov r12, qword ptr [rdi+40H] + mov r13, qword ptr [rdi+48H] + mov r14, qword ptr [rdi+50H] + mov r15, qword ptr [rdi+58H] + vmovdqu32 ymm24, ymmword ptr [r8+rdx-1H*20H] + vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-1H*20H], 01H + vmovdqu32 ymm25, ymmword ptr [r9+rdx-1H*20H] + vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-1H*20H], 01H + vpunpcklqdq zmm8, zmm24, zmm25 + vpunpckhqdq zmm9, zmm24, zmm25 + vmovdqu32 ymm24, ymmword ptr [r10+rdx-1H*20H] + vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-1H*20H], 01H + vmovdqu32 ymm25, ymmword ptr [r11+rdx-1H*20H] + vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-1H*20H], 01H + vpunpcklqdq zmm10, zmm24, zmm25 + vpunpckhqdq zmm11, zmm24, zmm25 + prefetcht0 byte ptr [r8+rdx+80H] + prefetcht0 byte ptr [r12+rdx+80H] + prefetcht0 byte ptr [r9+rdx+80H] + prefetcht0 byte ptr [r13+rdx+80H] + prefetcht0 byte ptr [r10+rdx+80H] + prefetcht0 byte ptr [r14+rdx+80H] + prefetcht0 byte ptr [r11+rdx+80H] + prefetcht0 byte ptr [r15+rdx+80H] + mov r8, qword ptr [rdi+20H] + mov r9, qword ptr [rdi+28H] + mov r10, qword ptr [rdi+30H] + mov r11, qword ptr [rdi+38H] + mov r12, qword ptr [rdi+60H] + mov r13, qword ptr [rdi+68H] + mov r14, qword ptr [rdi+70H] + mov r15, qword ptr [rdi+78H] + vmovdqu32 ymm24, ymmword ptr [r8+rdx-1H*20H] + vinserti64x4 zmm24, zmm24, ymmword ptr [r12+rdx-1H*20H], 01H + vmovdqu32 ymm25, ymmword ptr [r9+rdx-1H*20H] + vinserti64x4 zmm25, zmm25, ymmword ptr [r13+rdx-1H*20H], 01H + vpunpcklqdq zmm12, zmm24, zmm25 + vpunpckhqdq zmm13, zmm24, zmm25 + vmovdqu32 ymm24, ymmword ptr [r10+rdx-1H*20H] + vinserti64x4 zmm24, zmm24, ymmword ptr [r14+rdx-1H*20H], 01H + vmovdqu32 ymm25, ymmword ptr [r11+rdx-1H*20H] + vinserti64x4 zmm25, zmm25, ymmword ptr [r15+rdx-1H*20H], 01H + vpunpcklqdq zmm14, zmm24, zmm25 + vpunpckhqdq zmm15, zmm24, zmm25 + prefetcht0 byte ptr [r8+rdx+80H] + prefetcht0 byte ptr [r12+rdx+80H] + prefetcht0 byte ptr [r9+rdx+80H] + prefetcht0 byte ptr [r13+rdx+80H] + prefetcht0 byte ptr [r10+rdx+80H] + prefetcht0 byte ptr [r14+rdx+80H] + prefetcht0 byte ptr [r11+rdx+80H] + prefetcht0 byte ptr [r15+rdx+80H] + vshufps zmm24, zmm8, zmm10, 136 + vshufps zmm30, zmm12, zmm14, 136 + vmovdqa32 zmm28, zmm24 + vpermt2d zmm24, zmm27, zmm30 + vpermt2d zmm28, zmm31, zmm30 + vshufps zmm25, zmm8, zmm10, 221 + vshufps zmm30, zmm12, zmm14, 221 + vmovdqa32 zmm29, zmm25 + vpermt2d zmm25, zmm27, zmm30 + vpermt2d zmm29, zmm31, zmm30 + vshufps zmm26, zmm9, zmm11, 136 + vshufps zmm8, zmm13, zmm15, 136 + vmovdqa32 zmm30, zmm26 + vpermt2d zmm26, zmm27, zmm8 + vpermt2d zmm30, zmm31, zmm8 + vshufps zmm8, zmm9, zmm11, 221 + vshufps zmm10, zmm13, zmm15, 221 + vpermi2d zmm27, zmm8, zmm10 + vpermi2d zmm31, zmm8, zmm10 + vpbroadcastd zmm8, dword ptr [BLAKE3_IV_0] + vpbroadcastd zmm9, dword ptr [BLAKE3_IV_1] + vpbroadcastd zmm10, dword ptr [BLAKE3_IV_2] + vpbroadcastd zmm11, dword ptr [BLAKE3_IV_3] + vmovdqa32 zmm12, zmmword ptr [rsp] + vmovdqa32 zmm13, zmmword ptr [rsp+1H*40H] + vpbroadcastd zmm14, dword ptr [BLAKE3_BLOCK_LEN] + vpbroadcastd zmm15, dword ptr [rsp+22H*4H] + vpaddd zmm0, zmm0, zmm16 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm20 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm17 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm21 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm24 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm28 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm25 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm29 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm18 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm23 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm22 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm16 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm17 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm25 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm27 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm30 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm19 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm29 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm20 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm18 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm22 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm27 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm21 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm31 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm26 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm30 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm23 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm19 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm20 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm21 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm16 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm24 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm28 + vpaddd zmm1, zmm1, zmm25 + vpaddd zmm2, zmm2, zmm31 + vpaddd zmm3, zmm3, zmm30 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm29 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm26 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm23 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm16 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm18 + vpaddd zmm1, zmm1, zmm19 + vpaddd zmm2, zmm2, zmm17 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm25 + vpaddd zmm1, zmm1, zmm27 + vpaddd zmm2, zmm2, zmm24 + vpaddd zmm3, zmm3, zmm31 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm30 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm28 + vpaddd zmm3, zmm3, zmm17 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm29 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm18 + vpaddd zmm3, zmm3, zmm20 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm19 + vpaddd zmm1, zmm1, zmm26 + vpaddd zmm2, zmm2, zmm22 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpaddd zmm0, zmm0, zmm27 + vpaddd zmm1, zmm1, zmm21 + vpaddd zmm2, zmm2, zmm17 + vpaddd zmm3, zmm3, zmm24 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vprord zmm15, zmm15, 16 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 12 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vpaddd zmm0, zmm0, zmm31 + vpaddd zmm1, zmm1, zmm16 + vpaddd zmm2, zmm2, zmm25 + vpaddd zmm3, zmm3, zmm22 + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm1, zmm1, zmm5 + vpaddd zmm2, zmm2, zmm6 + vpaddd zmm3, zmm3, zmm7 + vpxord zmm12, zmm12, zmm0 + vpxord zmm13, zmm13, zmm1 + vpxord zmm14, zmm14, zmm2 + vpxord zmm15, zmm15, zmm3 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vprord zmm15, zmm15, 8 + vpaddd zmm8, zmm8, zmm12 + vpaddd zmm9, zmm9, zmm13 + vpaddd zmm10, zmm10, zmm14 + vpaddd zmm11, zmm11, zmm15 + vpxord zmm4, zmm4, zmm8 + vpxord zmm5, zmm5, zmm9 + vpxord zmm6, zmm6, zmm10 + vpxord zmm7, zmm7, zmm11 + vprord zmm4, zmm4, 7 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vpaddd zmm0, zmm0, zmm30 + vpaddd zmm1, zmm1, zmm18 + vpaddd zmm2, zmm2, zmm19 + vpaddd zmm3, zmm3, zmm23 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 16 + vprord zmm12, zmm12, 16 + vprord zmm13, zmm13, 16 + vprord zmm14, zmm14, 16 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 12 + vprord zmm6, zmm6, 12 + vprord zmm7, zmm7, 12 + vprord zmm4, zmm4, 12 + vpaddd zmm0, zmm0, zmm26 + vpaddd zmm1, zmm1, zmm28 + vpaddd zmm2, zmm2, zmm20 + vpaddd zmm3, zmm3, zmm29 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm1, zmm1, zmm6 + vpaddd zmm2, zmm2, zmm7 + vpaddd zmm3, zmm3, zmm4 + vpxord zmm15, zmm15, zmm0 + vpxord zmm12, zmm12, zmm1 + vpxord zmm13, zmm13, zmm2 + vpxord zmm14, zmm14, zmm3 + vprord zmm15, zmm15, 8 + vprord zmm12, zmm12, 8 + vprord zmm13, zmm13, 8 + vprord zmm14, zmm14, 8 + vpaddd zmm10, zmm10, zmm15 + vpaddd zmm11, zmm11, zmm12 + vpaddd zmm8, zmm8, zmm13 + vpaddd zmm9, zmm9, zmm14 + vpxord zmm5, zmm5, zmm10 + vpxord zmm6, zmm6, zmm11 + vpxord zmm7, zmm7, zmm8 + vpxord zmm4, zmm4, zmm9 + vprord zmm5, zmm5, 7 + vprord zmm6, zmm6, 7 + vprord zmm7, zmm7, 7 + vprord zmm4, zmm4, 7 + vpxord zmm0, zmm0, zmm8 + vpxord zmm1, zmm1, zmm9 + vpxord zmm2, zmm2, zmm10 + vpxord zmm3, zmm3, zmm11 + vpxord zmm4, zmm4, zmm12 + vpxord zmm5, zmm5, zmm13 + vpxord zmm6, zmm6, zmm14 + vpxord zmm7, zmm7, zmm15 + movzx eax, byte ptr [rbp+78H] + jne innerloop16 + mov rbx, qword ptr [rbp+90H] + vpunpckldq zmm16, zmm0, zmm1 + vpunpckhdq zmm17, zmm0, zmm1 + vpunpckldq zmm18, zmm2, zmm3 + vpunpckhdq zmm19, zmm2, zmm3 + vpunpckldq zmm20, zmm4, zmm5 + vpunpckhdq zmm21, zmm4, zmm5 + vpunpckldq zmm22, zmm6, zmm7 + vpunpckhdq zmm23, zmm6, zmm7 + vpunpcklqdq zmm0, zmm16, zmm18 + vpunpckhqdq zmm1, zmm16, zmm18 + vpunpcklqdq zmm2, zmm17, zmm19 + vpunpckhqdq zmm3, zmm17, zmm19 + vpunpcklqdq zmm4, zmm20, zmm22 + vpunpckhqdq zmm5, zmm20, zmm22 + vpunpcklqdq zmm6, zmm21, zmm23 + vpunpckhqdq zmm7, zmm21, zmm23 + vshufi32x4 zmm16, zmm0, zmm4, 88H + vshufi32x4 zmm17, zmm1, zmm5, 88H + vshufi32x4 zmm18, zmm2, zmm6, 88H + vshufi32x4 zmm19, zmm3, zmm7, 88H + vshufi32x4 zmm20, zmm0, zmm4, 0DDH + vshufi32x4 zmm21, zmm1, zmm5, 0DDH + vshufi32x4 zmm22, zmm2, zmm6, 0DDH + vshufi32x4 zmm23, zmm3, zmm7, 0DDH + vshufi32x4 zmm0, zmm16, zmm17, 88H + vshufi32x4 zmm1, zmm18, zmm19, 88H + vshufi32x4 zmm2, zmm20, zmm21, 88H + vshufi32x4 zmm3, zmm22, zmm23, 88H + vshufi32x4 zmm4, zmm16, zmm17, 0DDH + vshufi32x4 zmm5, zmm18, zmm19, 0DDH + vshufi32x4 zmm6, zmm20, zmm21, 0DDH + vshufi32x4 zmm7, zmm22, zmm23, 0DDH + vmovdqu32 zmmword ptr [rbx], zmm0 + vmovdqu32 zmmword ptr [rbx+1H*40H], zmm1 + vmovdqu32 zmmword ptr [rbx+2H*40H], zmm2 + vmovdqu32 zmmword ptr [rbx+3H*40H], zmm3 + vmovdqu32 zmmword ptr [rbx+4H*40H], zmm4 + vmovdqu32 zmmword ptr [rbx+5H*40H], zmm5 + vmovdqu32 zmmword ptr [rbx+6H*40H], zmm6 + vmovdqu32 zmmword ptr [rbx+7H*40H], zmm7 + vmovdqa32 zmm0, zmmword ptr [rsp] + vmovdqa32 zmm1, zmmword ptr [rsp+1H*40H] + vmovdqa32 zmm2, zmm0 + ; XXX: ml64.exe does not currently understand the syntax. We use a workaround. + vpbroadcastd zmm4, dword ptr [ADD16] + vpbroadcastd zmm5, dword ptr [ADD1] + vpaddd zmm2{k1}, zmm0, zmm4 + ; vpaddd zmm2{k1}, zmm0, dword ptr [ADD16] ; {1to16} + vpcmpud k2, zmm2, zmm0, 1 + vpaddd zmm1 {k2}, zmm1, zmm5 + ; vpaddd zmm1 {k2}, zmm1, dword ptr [ADD1] ; {1to16} + vmovdqa32 zmmword ptr [rsp], zmm2 + vmovdqa32 zmmword ptr [rsp+1H*40H], zmm1 + add rdi, 128 + add rbx, 512 + mov qword ptr [rbp+90H], rbx + sub rsi, 16 + cmp rsi, 16 + jnc outerloop16 + test rsi, rsi + jne final15blocks +unwind: + vzeroupper + vmovdqa xmm6, xmmword ptr [rsp+90H] + vmovdqa xmm7, xmmword ptr [rsp+0A0H] + vmovdqa xmm8, xmmword ptr [rsp+0B0H] + vmovdqa xmm9, xmmword ptr [rsp+0C0H] + vmovdqa xmm10, xmmword ptr [rsp+0D0H] + vmovdqa xmm11, xmmword ptr [rsp+0E0H] + vmovdqa xmm12, xmmword ptr [rsp+0F0H] + vmovdqa xmm13, xmmword ptr [rsp+100H] + vmovdqa xmm14, xmmword ptr [rsp+110H] + vmovdqa xmm15, xmmword ptr [rsp+120H] + mov rsp, rbp + pop rbp + pop rbx + pop rsi + pop rdi + pop r12 + pop r13 + pop r14 + pop r15 + ret +ALIGN 16 +final15blocks: + test esi, 8H + je final7blocks + vpbroadcastd ymm0, dword ptr [rcx] + vpbroadcastd ymm1, dword ptr [rcx+4H] + vpbroadcastd ymm2, dword ptr [rcx+8H] + vpbroadcastd ymm3, dword ptr [rcx+0CH] + vpbroadcastd ymm4, dword ptr [rcx+10H] + vpbroadcastd ymm5, dword ptr [rcx+14H] + vpbroadcastd ymm6, dword ptr [rcx+18H] + vpbroadcastd ymm7, dword ptr [rcx+1CH] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + mov r10, qword ptr [rdi+10H] + mov r11, qword ptr [rdi+18H] + mov r12, qword ptr [rdi+20H] + mov r13, qword ptr [rdi+28H] + mov r14, qword ptr [rdi+30H] + mov r15, qword ptr [rdi+38H] + movzx eax, byte ptr [rbp+78H] + movzx ebx, byte ptr [rbp+80H] + or eax, ebx + xor edx, edx +innerloop8: + movzx ebx, byte ptr [rbp+88H] + or ebx, eax + add rdx, 64 + cmp rdx, qword ptr [rsp+80H] + cmove eax, ebx + mov dword ptr [rsp+88H], eax + vmovups xmm8, xmmword ptr [r8+rdx-40H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-40H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-40H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-40H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-40H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-40H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-40H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-40H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm16, ymm12, ymm14, 136 + vshufps ymm17, ymm12, ymm14, 221 + vshufps ymm18, ymm13, ymm15, 136 + vshufps ymm19, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-30H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-30H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-30H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-30H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-30H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-30H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-30H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-30H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm20, ymm12, ymm14, 136 + vshufps ymm21, ymm12, ymm14, 221 + vshufps ymm22, ymm13, ymm15, 136 + vshufps ymm23, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-20H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-20H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-20H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-20H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-20H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-20H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-20H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-20H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm24, ymm12, ymm14, 136 + vshufps ymm25, ymm12, ymm14, 221 + vshufps ymm26, ymm13, ymm15, 136 + vshufps ymm27, ymm13, ymm15, 221 + vmovups xmm8, xmmword ptr [r8+rdx-10H] + vinsertf128 ymm8, ymm8, xmmword ptr [r12+rdx-10H], 01H + vmovups xmm9, xmmword ptr [r9+rdx-10H] + vinsertf128 ymm9, ymm9, xmmword ptr [r13+rdx-10H], 01H + vunpcklpd ymm12, ymm8, ymm9 + vunpckhpd ymm13, ymm8, ymm9 + vmovups xmm10, xmmword ptr [r10+rdx-10H] + vinsertf128 ymm10, ymm10, xmmword ptr [r14+rdx-10H], 01H + vmovups xmm11, xmmword ptr [r11+rdx-10H] + vinsertf128 ymm11, ymm11, xmmword ptr [r15+rdx-10H], 01H + vunpcklpd ymm14, ymm10, ymm11 + vunpckhpd ymm15, ymm10, ymm11 + vshufps ymm28, ymm12, ymm14, 136 + vshufps ymm29, ymm12, ymm14, 221 + vshufps ymm30, ymm13, ymm15, 136 + vshufps ymm31, ymm13, ymm15, 221 + vpbroadcastd ymm8, dword ptr [BLAKE3_IV_0] + vpbroadcastd ymm9, dword ptr [BLAKE3_IV_1] + vpbroadcastd ymm10, dword ptr [BLAKE3_IV_2] + vpbroadcastd ymm11, dword ptr [BLAKE3_IV_3] + vmovdqa ymm12, ymmword ptr [rsp] + vmovdqa ymm13, ymmword ptr [rsp+40H] + vpbroadcastd ymm14, dword ptr [BLAKE3_BLOCK_LEN] + vpbroadcastd ymm15, dword ptr [rsp+88H] + vpaddd ymm0, ymm0, ymm16 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm20 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm17 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm21 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm24 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm28 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm25 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm29 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm18 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm23 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm22 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm16 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm17 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm25 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm27 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm30 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm19 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm29 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm20 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm18 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm22 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm27 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm21 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm31 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm26 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm30 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm23 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm19 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm20 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm21 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm16 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm24 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm28 + vpaddd ymm1, ymm1, ymm25 + vpaddd ymm2, ymm2, ymm31 + vpaddd ymm3, ymm3, ymm30 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm29 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm26 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm23 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm16 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm18 + vpaddd ymm1, ymm1, ymm19 + vpaddd ymm2, ymm2, ymm17 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm25 + vpaddd ymm1, ymm1, ymm27 + vpaddd ymm2, ymm2, ymm24 + vpaddd ymm3, ymm3, ymm31 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm30 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm28 + vpaddd ymm3, ymm3, ymm17 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm29 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm18 + vpaddd ymm3, ymm3, ymm20 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm19 + vpaddd ymm1, ymm1, ymm26 + vpaddd ymm2, ymm2, ymm22 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpaddd ymm0, ymm0, ymm27 + vpaddd ymm1, ymm1, ymm21 + vpaddd ymm2, ymm2, ymm17 + vpaddd ymm3, ymm3, ymm24 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vprord ymm15, ymm15, 16 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 12 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vpaddd ymm0, ymm0, ymm31 + vpaddd ymm1, ymm1, ymm16 + vpaddd ymm2, ymm2, ymm25 + vpaddd ymm3, ymm3, ymm22 + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm1, ymm1, ymm5 + vpaddd ymm2, ymm2, ymm6 + vpaddd ymm3, ymm3, ymm7 + vpxord ymm12, ymm12, ymm0 + vpxord ymm13, ymm13, ymm1 + vpxord ymm14, ymm14, ymm2 + vpxord ymm15, ymm15, ymm3 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vprord ymm15, ymm15, 8 + vpaddd ymm8, ymm8, ymm12 + vpaddd ymm9, ymm9, ymm13 + vpaddd ymm10, ymm10, ymm14 + vpaddd ymm11, ymm11, ymm15 + vpxord ymm4, ymm4, ymm8 + vpxord ymm5, ymm5, ymm9 + vpxord ymm6, ymm6, ymm10 + vpxord ymm7, ymm7, ymm11 + vprord ymm4, ymm4, 7 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vpaddd ymm0, ymm0, ymm30 + vpaddd ymm1, ymm1, ymm18 + vpaddd ymm2, ymm2, ymm19 + vpaddd ymm3, ymm3, ymm23 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 16 + vprord ymm12, ymm12, 16 + vprord ymm13, ymm13, 16 + vprord ymm14, ymm14, 16 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 12 + vprord ymm6, ymm6, 12 + vprord ymm7, ymm7, 12 + vprord ymm4, ymm4, 12 + vpaddd ymm0, ymm0, ymm26 + vpaddd ymm1, ymm1, ymm28 + vpaddd ymm2, ymm2, ymm20 + vpaddd ymm3, ymm3, ymm29 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm1, ymm1, ymm6 + vpaddd ymm2, ymm2, ymm7 + vpaddd ymm3, ymm3, ymm4 + vpxord ymm15, ymm15, ymm0 + vpxord ymm12, ymm12, ymm1 + vpxord ymm13, ymm13, ymm2 + vpxord ymm14, ymm14, ymm3 + vprord ymm15, ymm15, 8 + vprord ymm12, ymm12, 8 + vprord ymm13, ymm13, 8 + vprord ymm14, ymm14, 8 + vpaddd ymm10, ymm10, ymm15 + vpaddd ymm11, ymm11, ymm12 + vpaddd ymm8, ymm8, ymm13 + vpaddd ymm9, ymm9, ymm14 + vpxord ymm5, ymm5, ymm10 + vpxord ymm6, ymm6, ymm11 + vpxord ymm7, ymm7, ymm8 + vpxord ymm4, ymm4, ymm9 + vprord ymm5, ymm5, 7 + vprord ymm6, ymm6, 7 + vprord ymm7, ymm7, 7 + vprord ymm4, ymm4, 7 + vpxor ymm0, ymm0, ymm8 + vpxor ymm1, ymm1, ymm9 + vpxor ymm2, ymm2, ymm10 + vpxor ymm3, ymm3, ymm11 + vpxor ymm4, ymm4, ymm12 + vpxor ymm5, ymm5, ymm13 + vpxor ymm6, ymm6, ymm14 + vpxor ymm7, ymm7, ymm15 + movzx eax, byte ptr [rbp+78H] + jne innerloop8 + mov rbx, qword ptr [rbp+90H] + vunpcklps ymm8, ymm0, ymm1 + vunpcklps ymm9, ymm2, ymm3 + vunpckhps ymm10, ymm0, ymm1 + vunpcklps ymm11, ymm4, ymm5 + vunpcklps ymm0, ymm6, ymm7 + vshufps ymm12, ymm8, ymm9, 78 + vblendps ymm1, ymm8, ymm12, 0CCH + vshufps ymm8, ymm11, ymm0, 78 + vunpckhps ymm13, ymm2, ymm3 + vblendps ymm2, ymm11, ymm8, 0CCH + vblendps ymm3, ymm12, ymm9, 0CCH + vperm2f128 ymm12, ymm1, ymm2, 20H + vmovups ymmword ptr [rbx], ymm12 + vunpckhps ymm14, ymm4, ymm5 + vblendps ymm4, ymm8, ymm0, 0CCH + vunpckhps ymm15, ymm6, ymm7 + vperm2f128 ymm7, ymm3, ymm4, 20H + vmovups ymmword ptr [rbx+20H], ymm7 + vshufps ymm5, ymm10, ymm13, 78 + vblendps ymm6, ymm5, ymm13, 0CCH + vshufps ymm13, ymm14, ymm15, 78 + vblendps ymm10, ymm10, ymm5, 0CCH + vblendps ymm14, ymm14, ymm13, 0CCH + vperm2f128 ymm8, ymm10, ymm14, 20H + vmovups ymmword ptr [rbx+40H], ymm8 + vblendps ymm15, ymm13, ymm15, 0CCH + vperm2f128 ymm13, ymm6, ymm15, 20H + vmovups ymmword ptr [rbx+60H], ymm13 + vperm2f128 ymm9, ymm1, ymm2, 31H + vperm2f128 ymm11, ymm3, ymm4, 31H + vmovups ymmword ptr [rbx+80H], ymm9 + vperm2f128 ymm14, ymm10, ymm14, 31H + vperm2f128 ymm15, ymm6, ymm15, 31H + vmovups ymmword ptr [rbx+0A0H], ymm11 + vmovups ymmword ptr [rbx+0C0H], ymm14 + vmovups ymmword ptr [rbx+0E0H], ymm15 + vmovdqa ymm0, ymmword ptr [rsp] + vmovdqa ymm2, ymmword ptr [rsp+40H] + vmovdqa32 ymm0 {k1}, ymmword ptr [rsp+1H*20H] + vmovdqa32 ymm2 {k1}, ymmword ptr [rsp+3H*20H] + vmovdqa ymmword ptr [rsp], ymm0 + vmovdqa ymmword ptr [rsp+40H], ymm2 + add rbx, 256 + mov qword ptr [rbp+90H], rbx + add rdi, 64 + sub rsi, 8 +final7blocks: + mov rbx, qword ptr [rbp+90H] + mov r15, qword ptr [rsp+80H] + movzx r13, byte ptr [rbp+78H] + movzx r12, byte ptr [rbp+88H] + test esi, 4H + je final3blocks + vbroadcasti32x4 zmm0, xmmword ptr [rcx] + vbroadcasti32x4 zmm1, xmmword ptr [rcx+1H*10H] + vmovdqa xmm12, xmmword ptr [rsp] + vmovdqa xmm13, xmmword ptr [rsp+40H] + vpunpckldq xmm14, xmm12, xmm13 + vpunpckhdq xmm15, xmm12, xmm13 + vpermq ymm14, ymm14, 0DCH + vpermq ymm15, ymm15, 0DCH + vpbroadcastd zmm12, dword ptr [BLAKE3_BLOCK_LEN] + vinserti64x4 zmm13, zmm14, ymm15, 01H + mov eax, 17476 + kmovw k2, eax + vpblendmd zmm13 {k2}, zmm13, zmm12 + vbroadcasti32x4 zmm15, xmmword ptr [BLAKE3_IV] + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + mov r10, qword ptr [rdi+10H] + mov r11, qword ptr [rdi+18H] + mov eax, 43690 + kmovw k3, eax + mov eax, 34952 + kmovw k4, eax + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +ALIGN 16 +innerloop4: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+88H], eax + vmovdqa32 zmm2, zmm15 + vpbroadcastd zmm8, dword ptr [rsp+22H*4H] + vpblendmd zmm3 {k4}, zmm13, zmm8 + vmovups zmm8, zmmword ptr [r8+rdx-1H*40H] + vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-4H*10H], 01H + vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-4H*10H], 02H + vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-4H*10H], 03H + vmovups zmm9, zmmword ptr [r8+rdx-30H] + vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-3H*10H], 01H + vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-3H*10H], 02H + vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-3H*10H], 03H + vshufps zmm4, zmm8, zmm9, 136 + vshufps zmm5, zmm8, zmm9, 221 + vmovups zmm8, zmmword ptr [r8+rdx-20H] + vinserti32x4 zmm8, zmm8, xmmword ptr [r9+rdx-2H*10H], 01H + vinserti32x4 zmm8, zmm8, xmmword ptr [r10+rdx-2H*10H], 02H + vinserti32x4 zmm8, zmm8, xmmword ptr [r11+rdx-2H*10H], 03H + vmovups zmm9, zmmword ptr [r8+rdx-10H] + vinserti32x4 zmm9, zmm9, xmmword ptr [r9+rdx-1H*10H], 01H + vinserti32x4 zmm9, zmm9, xmmword ptr [r10+rdx-1H*10H], 02H + vinserti32x4 zmm9, zmm9, xmmword ptr [r11+rdx-1H*10H], 03H + vshufps zmm6, zmm8, zmm9, 136 + vshufps zmm7, zmm8, zmm9, 221 + vpshufd zmm6, zmm6, 93H + vpshufd zmm7, zmm7, 93H + mov al, 7 +roundloop4: + vpaddd zmm0, zmm0, zmm4 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 16 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 12 + vpaddd zmm0, zmm0, zmm5 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 8 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 7 + vpshufd zmm0, zmm0, 93H + vpshufd zmm3, zmm3, 4EH + vpshufd zmm2, zmm2, 39H + vpaddd zmm0, zmm0, zmm6 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 16 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 12 + vpaddd zmm0, zmm0, zmm7 + vpaddd zmm0, zmm0, zmm1 + vpxord zmm3, zmm3, zmm0 + vprord zmm3, zmm3, 8 + vpaddd zmm2, zmm2, zmm3 + vpxord zmm1, zmm1, zmm2 + vprord zmm1, zmm1, 7 + vpshufd zmm0, zmm0, 39H + vpshufd zmm3, zmm3, 4EH + vpshufd zmm2, zmm2, 93H + dec al + jz endroundloop4 + vshufps zmm8, zmm4, zmm5, 214 + vpshufd zmm9, zmm4, 0FH + vpshufd zmm4, zmm8, 39H + vshufps zmm8, zmm6, zmm7, 250 + vpblendmd zmm9 {k3}, zmm9, zmm8 + vpunpcklqdq zmm8, zmm7, zmm5 + vpblendmd zmm8 {k4}, zmm8, zmm6 + vpshufd zmm8, zmm8, 78H + vpunpckhdq zmm5, zmm5, zmm7 + vpunpckldq zmm6, zmm6, zmm5 + vpshufd zmm7, zmm6, 1EH + vmovdqa32 zmm5, zmm9 + vmovdqa32 zmm6, zmm8 + jmp roundloop4 +endroundloop4: + vpxord zmm0, zmm0, zmm2 + vpxord zmm1, zmm1, zmm3 + mov eax, r13d + cmp rdx, r15 + jne innerloop4 + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+10H], xmm1 + vextracti128 xmmword ptr [rbx+20H], ymm0, 01H + vextracti128 xmmword ptr [rbx+30H], ymm1, 01H + vextracti32x4 xmmword ptr [rbx+4H*10H], zmm0, 02H + vextracti32x4 xmmword ptr [rbx+5H*10H], zmm1, 02H + vextracti32x4 xmmword ptr [rbx+6H*10H], zmm0, 03H + vextracti32x4 xmmword ptr [rbx+7H*10H], zmm1, 03H + vmovdqa xmm0, xmmword ptr [rsp] + vmovdqa xmm2, xmmword ptr [rsp+40H] + vmovdqa32 xmm0 {k1}, xmmword ptr [rsp+1H*10H] + vmovdqa32 xmm2 {k1}, xmmword ptr [rsp+5H*10H] + vmovdqa xmmword ptr [rsp], xmm0 + vmovdqa xmmword ptr [rsp+40H], xmm2 + add rbx, 128 + add rdi, 32 + sub rsi, 4 +final3blocks: + test esi, 2H + je final1block + vbroadcasti128 ymm0, xmmword ptr [rcx] + vbroadcasti128 ymm1, xmmword ptr [rcx+10H] + vmovd xmm13, dword ptr [rsp] + vpinsrd xmm13, xmm13, dword ptr [rsp+40H], 1 + vpinsrd xmm13, xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 + vmovd xmm14, dword ptr [rsp+4H] + vpinsrd xmm14, xmm14, dword ptr [rsp+44H], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 + vinserti128 ymm13, ymm13, xmm14, 01H + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +ALIGN 16 +innerloop2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + mov dword ptr [rsp+88H], eax + vbroadcasti128 ymm2, xmmword ptr [BLAKE3_IV] + vpbroadcastd ymm8, dword ptr [rsp+88H] + vpblendd ymm3, ymm13, ymm8, 88H + vmovups ymm8, ymmword ptr [r8+rdx-40H] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-40H], 01H + vmovups ymm9, ymmword ptr [r8+rdx-30H] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-30H], 01H + vshufps ymm4, ymm8, ymm9, 136 + vshufps ymm5, ymm8, ymm9, 221 + vmovups ymm8, ymmword ptr [r8+rdx-20H] + vinsertf128 ymm8, ymm8, xmmword ptr [r9+rdx-20H], 01H + vmovups ymm9, ymmword ptr [r8+rdx-10H] + vinsertf128 ymm9, ymm9, xmmword ptr [r9+rdx-10H], 01H + vshufps ymm6, ymm8, ymm9, 136 + vshufps ymm7, ymm8, ymm9, 221 + vpshufd ymm6, ymm6, 93H + vpshufd ymm7, ymm7, 93H + mov al, 7 +roundloop2: + vpaddd ymm0, ymm0, ymm4 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 16 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 12 + vpaddd ymm0, ymm0, ymm5 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 8 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 7 + vpshufd ymm0, ymm0, 93H + vpshufd ymm3, ymm3, 4EH + vpshufd ymm2, ymm2, 39H + vpaddd ymm0, ymm0, ymm6 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 16 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 12 + vpaddd ymm0, ymm0, ymm7 + vpaddd ymm0, ymm0, ymm1 + vpxord ymm3, ymm3, ymm0 + vprord ymm3, ymm3, 8 + vpaddd ymm2, ymm2, ymm3 + vpxord ymm1, ymm1, ymm2 + vprord ymm1, ymm1, 7 + vpshufd ymm0, ymm0, 39H + vpshufd ymm3, ymm3, 4EH + vpshufd ymm2, ymm2, 93H + dec al + jz endroundloop2 + vshufps ymm8, ymm4, ymm5, 214 + vpshufd ymm9, ymm4, 0FH + vpshufd ymm4, ymm8, 39H + vshufps ymm8, ymm6, ymm7, 250 + vpblendd ymm9, ymm9, ymm8, 0AAH + vpunpcklqdq ymm8, ymm7, ymm5 + vpblendd ymm8, ymm8, ymm6, 88H + vpshufd ymm8, ymm8, 78H + vpunpckhdq ymm5, ymm5, ymm7 + vpunpckldq ymm6, ymm6, ymm5 + vpshufd ymm7, ymm6, 1EH + vmovdqa ymm5, ymm9 + vmovdqa ymm6, ymm8 + jmp roundloop2 +endroundloop2: + vpxor ymm0, ymm0, ymm2 + vpxor ymm1, ymm1, ymm3 + mov eax, r13d + cmp rdx, r15 + jne innerloop2 + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+10H], xmm1 + vextracti128 xmmword ptr [rbx+20H], ymm0, 01H + vextracti128 xmmword ptr [rbx+30H], ymm1, 01H + vmovdqa xmm0, xmmword ptr [rsp] + vmovdqa xmm2, xmmword ptr [rsp+40H] + vmovdqu32 xmm0 {k1}, xmmword ptr [rsp+8H] + vmovdqu32 xmm2 {k1}, xmmword ptr [rsp+48H] + vmovdqa xmmword ptr [rsp], xmm0 + vmovdqa xmmword ptr [rsp+40H], xmm2 + add rbx, 64 + add rdi, 16 + sub rsi, 2 +final1block: + test esi, 1H + je unwind + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+10H] + vmovd xmm14, dword ptr [rsp] + vpinsrd xmm14, xmm14, dword ptr [rsp+40H], 1 + vpinsrd xmm14, xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 + vmovdqa xmm15, xmmword ptr [BLAKE3_IV] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +ALIGN 16 +innerloop1: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + vpinsrd xmm3, xmm14, eax, 3 + vmovdqa xmm2, xmm15 + vmovups xmm8, xmmword ptr [r8+rdx-40H] + vmovups xmm9, xmmword ptr [r8+rdx-30H] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [r8+rdx-20H] + vmovups xmm9, xmmword ptr [r8+rdx-10H] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 93H + vpshufd xmm7, xmm7, 93H + mov al, 7 +roundloop1: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 93H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 39H + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 39H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 93H + dec al + jz endroundloop1 + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0FH + vpshufd xmm4, xmm8, 39H + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0AAH + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 88H + vpshufd xmm8, xmm8, 78H + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 1EH + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp roundloop1 +endroundloop1: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne innerloop1 + vmovdqu xmmword ptr [rbx], xmm0 + vmovdqu xmmword ptr [rbx+10H], xmm1 + jmp unwind + +_blake3_hash_many_avx512 ENDP +blake3_hash_many_avx512 ENDP + +ALIGN 16 +blake3_compress_in_place_avx512 PROC +_blake3_compress_in_place_avx512 PROC + sub rsp, 72 + vmovdqa xmmword ptr [rsp], xmm6 + vmovdqa xmmword ptr [rsp+10H], xmm7 + vmovdqa xmmword ptr [rsp+20H], xmm8 + vmovdqa xmmword ptr [rsp+30H], xmm9 + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+10H] + movzx eax, byte ptr [rsp+70H] + movzx r8d, r8b + shl rax, 32 + add r8, rax + vmovq xmm3, r9 + vmovq xmm4, r8 + vpunpcklqdq xmm3, xmm3, xmm4 + vmovaps xmm2, xmmword ptr [BLAKE3_IV] + vmovups xmm8, xmmword ptr [rdx] + vmovups xmm9, xmmword ptr [rdx+10H] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [rdx+20H] + vmovups xmm9, xmmword ptr [rdx+30H] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 93H + vpshufd xmm7, xmm7, 93H + mov al, 7 +@@: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 93H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 39H + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 39H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 93H + dec al + jz @F + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0FH + vpshufd xmm4, xmm8, 39H + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0AAH + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 88H + vpshufd xmm8, xmm8, 78H + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 1EH + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp @B +@@: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + vmovdqu xmmword ptr [rcx], xmm0 + vmovdqu xmmword ptr [rcx+10H], xmm1 + vmovdqa xmm6, xmmword ptr [rsp] + vmovdqa xmm7, xmmword ptr [rsp+10H] + vmovdqa xmm8, xmmword ptr [rsp+20H] + vmovdqa xmm9, xmmword ptr [rsp+30H] + add rsp, 72 + ret +_blake3_compress_in_place_avx512 ENDP +blake3_compress_in_place_avx512 ENDP + +ALIGN 16 +blake3_compress_xof_avx512 PROC +_blake3_compress_xof_avx512 PROC + sub rsp, 72 + vmovdqa xmmword ptr [rsp], xmm6 + vmovdqa xmmword ptr [rsp+10H], xmm7 + vmovdqa xmmword ptr [rsp+20H], xmm8 + vmovdqa xmmword ptr [rsp+30H], xmm9 + vmovdqu xmm0, xmmword ptr [rcx] + vmovdqu xmm1, xmmword ptr [rcx+10H] + movzx eax, byte ptr [rsp+70H] + movzx r8d, r8b + mov r10, qword ptr [rsp+78H] + shl rax, 32 + add r8, rax + vmovq xmm3, r9 + vmovq xmm4, r8 + vpunpcklqdq xmm3, xmm3, xmm4 + vmovaps xmm2, xmmword ptr [BLAKE3_IV] + vmovups xmm8, xmmword ptr [rdx] + vmovups xmm9, xmmword ptr [rdx+10H] + vshufps xmm4, xmm8, xmm9, 136 + vshufps xmm5, xmm8, xmm9, 221 + vmovups xmm8, xmmword ptr [rdx+20H] + vmovups xmm9, xmmword ptr [rdx+30H] + vshufps xmm6, xmm8, xmm9, 136 + vshufps xmm7, xmm8, xmm9, 221 + vpshufd xmm6, xmm6, 93H + vpshufd xmm7, xmm7, 93H + mov al, 7 +@@: + vpaddd xmm0, xmm0, xmm4 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm5 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 93H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 39H + vpaddd xmm0, xmm0, xmm6 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 16 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 12 + vpaddd xmm0, xmm0, xmm7 + vpaddd xmm0, xmm0, xmm1 + vpxord xmm3, xmm3, xmm0 + vprord xmm3, xmm3, 8 + vpaddd xmm2, xmm2, xmm3 + vpxord xmm1, xmm1, xmm2 + vprord xmm1, xmm1, 7 + vpshufd xmm0, xmm0, 39H + vpshufd xmm3, xmm3, 4EH + vpshufd xmm2, xmm2, 93H + dec al + jz @F + vshufps xmm8, xmm4, xmm5, 214 + vpshufd xmm9, xmm4, 0FH + vpshufd xmm4, xmm8, 39H + vshufps xmm8, xmm6, xmm7, 250 + vpblendd xmm9, xmm9, xmm8, 0AAH + vpunpcklqdq xmm8, xmm7, xmm5 + vpblendd xmm8, xmm8, xmm6, 88H + vpshufd xmm8, xmm8, 78H + vpunpckhdq xmm5, xmm5, xmm7 + vpunpckldq xmm6, xmm6, xmm5 + vpshufd xmm7, xmm6, 1EH + vmovdqa xmm5, xmm9 + vmovdqa xmm6, xmm8 + jmp @B +@@: + vpxor xmm0, xmm0, xmm2 + vpxor xmm1, xmm1, xmm3 + vpxor xmm2, xmm2, xmmword ptr [rcx] + vpxor xmm3, xmm3, xmmword ptr [rcx+10H] + vmovdqu xmmword ptr [r10], xmm0 + vmovdqu xmmword ptr [r10+10H], xmm1 + vmovdqu xmmword ptr [r10+20H], xmm2 + vmovdqu xmmword ptr [r10+30H], xmm3 + vmovdqa xmm6, xmmword ptr [rsp] + vmovdqa xmm7, xmmword ptr [rsp+10H] + vmovdqa xmm8, xmmword ptr [rsp+20H] + vmovdqa xmm9, xmmword ptr [rsp+30H] + add rsp, 72 + ret +_blake3_compress_xof_avx512 ENDP +blake3_compress_xof_avx512 ENDP + +_TEXT ENDS + +_RDATA SEGMENT READONLY PAGE ALIAS(".rdata") 'CONST' +ALIGN 64 +INDEX0: + dd 0, 1, 2, 3, 16, 17, 18, 19 + dd 8, 9, 10, 11, 24, 25, 26, 27 +INDEX1: + dd 4, 5, 6, 7, 20, 21, 22, 23 + dd 12, 13, 14, 15, 28, 29, 30, 31 +ADD0: + dd 0, 1, 2, 3, 4, 5, 6, 7 + dd 8, 9, 10, 11, 12, 13, 14, 15 +ADD1: + dd 1 +ADD16: + dd 16 +BLAKE3_BLOCK_LEN: + dd 64 +ALIGN 64 +BLAKE3_IV: +BLAKE3_IV_0: + dd 06A09E667H +BLAKE3_IV_1: + dd 0BB67AE85H +BLAKE3_IV_2: + dd 03C6EF372H +BLAKE3_IV_3: + dd 0A54FF53AH + +_RDATA ENDS +END diff --git a/src/Native/libmultihash/blake3/blake3_dispatch.c b/src/Native/libmultihash/blake3/blake3_dispatch.c new file mode 100644 index 000000000..684772564 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_dispatch.c @@ -0,0 +1,245 @@ +#include +#include +#include + +#include "blake3_impl.h" + +#if defined(IS_X86) +#if defined(_MSC_VER) +#include +#elif defined(__GNUC__) +#include +#else +#error "Unimplemented!" +#endif +#endif + +#if defined(IS_X86) +static uint64_t xgetbv() { +#if defined(_MSC_VER) + return _xgetbv(0); +#else + uint32_t eax = 0, edx = 0; + __asm__ __volatile__("xgetbv\n" : "=a"(eax), "=d"(edx) : "c"(0)); + return ((uint64_t)edx << 32) | eax; +#endif +} + +static void cpuid(uint32_t out[4], uint32_t id) { +#if defined(_MSC_VER) + __cpuid((int *)out, id); +#elif defined(__i386__) || defined(_M_IX86) + __asm__ __volatile__("movl %%ebx, %1\n" + "cpuid\n" + "xchgl %1, %%ebx\n" + : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) + : "a"(id)); +#else + __asm__ __volatile__("cpuid\n" + : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) + : "a"(id)); +#endif +} + +static void cpuidex(uint32_t out[4], uint32_t id, uint32_t sid) { +#if defined(_MSC_VER) + __cpuidex((int *)out, id, sid); +#elif defined(__i386__) || defined(_M_IX86) + __asm__ __volatile__("movl %%ebx, %1\n" + "cpuid\n" + "xchgl %1, %%ebx\n" + : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) + : "a"(id), "c"(sid)); +#else + __asm__ __volatile__("cpuid\n" + : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) + : "a"(id), "c"(sid)); +#endif +} + +#endif + +enum cpu_feature { + SSE2 = 1 << 0, + SSSE3 = 1 << 1, + SSE41 = 1 << 2, + AVX = 1 << 3, + AVX2 = 1 << 4, + AVX512F = 1 << 5, + AVX512VL = 1 << 6, + /* ... */ + UNDEFINED = 1 << 30 +}; + +#if !defined(BLAKE3_TESTING) +static /* Allow the variable to be controlled manually for testing */ +#endif + enum cpu_feature g_cpu_features = UNDEFINED; + +#if !defined(BLAKE3_TESTING) +static +#endif + enum cpu_feature + get_cpu_features() { + + if (g_cpu_features != UNDEFINED) { + return g_cpu_features; + } else { +#if defined(IS_X86) + uint32_t regs[4] = {0}; + uint32_t *eax = ®s[0], *ebx = ®s[1], *ecx = ®s[2], *edx = ®s[3]; + (void)edx; + enum cpu_feature features = 0; + cpuid(regs, 0); + const int max_id = *eax; + cpuid(regs, 1); +#if defined(__amd64__) || defined(_M_X64) + features |= SSE2; +#else + if (*edx & (1UL << 26)) + features |= SSE2; +#endif + if (*ecx & (1UL << 0)) + features |= SSSE3; + if (*ecx & (1UL << 19)) + features |= SSE41; + + if (*ecx & (1UL << 27)) { // OSXSAVE + const uint64_t mask = xgetbv(); + if ((mask & 6) == 6) { // SSE and AVX states + if (*ecx & (1UL << 28)) + features |= AVX; + if (max_id >= 7) { + cpuidex(regs, 7, 0); + if (*ebx & (1UL << 5)) + features |= AVX2; + if ((mask & 224) == 224) { // Opmask, ZMM_Hi256, Hi16_Zmm + if (*ebx & (1UL << 31)) + features |= AVX512VL; + if (*ebx & (1UL << 16)) + features |= AVX512F; + } + } + } + } + g_cpu_features = features; + return features; +#else + /* How to detect NEON? */ + return 0; +#endif + } +} + +void blake3_compress_in_place(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags) { +#if defined(IS_X86) + const enum cpu_feature features = get_cpu_features(); +#if !defined(BLAKE3_NO_AVX512) + if (features & AVX512VL) { + blake3_compress_in_place_avx512(cv, block, block_len, counter, flags); + return; + } +#endif +#if !defined(BLAKE3_NO_SSE41) + if (features & SSE41) { + blake3_compress_in_place_sse41(cv, block, block_len, counter, flags); + return; + } +#endif +#endif + blake3_compress_in_place_portable(cv, block, block_len, counter, flags); +} + +void blake3_compress_xof(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags, + uint8_t out[64]) { +#if defined(IS_X86) + const enum cpu_feature features = get_cpu_features(); +#if !defined(BLAKE3_NO_AVX512) + if (features & AVX512VL) { + blake3_compress_xof_avx512(cv, block, block_len, counter, flags, out); + return; + } +#endif +#if !defined(BLAKE3_NO_SSE41) + if (features & SSE41) { + blake3_compress_xof_sse41(cv, block, block_len, counter, flags, out); + return; + } +#endif +#endif + blake3_compress_xof_portable(cv, block, block_len, counter, flags, out); +} + +void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, uint8_t *out) { +#if defined(IS_X86) + const enum cpu_feature features = get_cpu_features(); +#if !defined(BLAKE3_NO_AVX512) + if ((features & (AVX512F|AVX512VL)) == (AVX512F|AVX512VL)) { + blake3_hash_many_avx512(inputs, num_inputs, blocks, key, counter, + increment_counter, flags, flags_start, flags_end, + out); + return; + } +#endif +#if !defined(BLAKE3_NO_AVX2) + if (features & AVX2) { + blake3_hash_many_avx2(inputs, num_inputs, blocks, key, counter, + increment_counter, flags, flags_start, flags_end, + out); + return; + } +#endif +#if !defined(BLAKE3_NO_SSE41) + if (features & SSE41) { + blake3_hash_many_sse41(inputs, num_inputs, blocks, key, counter, + increment_counter, flags, flags_start, flags_end, + out); + return; + } +#endif +#endif + +#if defined(BLAKE3_USE_NEON) + blake3_hash_many_neon(inputs, num_inputs, blocks, key, counter, + increment_counter, flags, flags_start, flags_end, out); + return; +#endif + + blake3_hash_many_portable(inputs, num_inputs, blocks, key, counter, + increment_counter, flags, flags_start, flags_end, + out); +} + +// The dynamically detected SIMD degree of the current platform. +size_t blake3_simd_degree(void) { +#if defined(IS_X86) + const enum cpu_feature features = get_cpu_features(); +#if !defined(BLAKE3_NO_AVX512) + if ((features & (AVX512F|AVX512VL)) == (AVX512F|AVX512VL)) { + return 16; + } +#endif +#if !defined(BLAKE3_NO_AVX2) + if (features & AVX2) { + return 8; + } +#endif +#if !defined(BLAKE3_NO_SSE41) + if (features & SSE41) { + return 4; + } +#endif +#endif +#if defined(BLAKE3_USE_NEON) + return 4; +#endif + return 1; +} diff --git a/src/Native/libmultihash/blake3/blake3_impl.h b/src/Native/libmultihash/blake3/blake3_impl.h new file mode 100644 index 000000000..c384671f0 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_impl.h @@ -0,0 +1,235 @@ +#ifndef BLAKE3_IMPL_H +#define BLAKE3_IMPL_H + +#include +#include +#include +#include +#include + +#include "blake3.h" + +// internal flags +enum blake3_flags { + CHUNK_START = 1 << 0, + CHUNK_END = 1 << 1, + PARENT = 1 << 2, + ROOT = 1 << 3, + KEYED_HASH = 1 << 4, + DERIVE_KEY_CONTEXT = 1 << 5, + DERIVE_KEY_MATERIAL = 1 << 6, +}; + +// This C implementation tries to support recent versions of GCC, Clang, and +// MSVC. +#if defined(_MSC_VER) +#define INLINE static __forceinline +#else +#define INLINE static inline __attribute__((always_inline)) +#endif + +#if defined(__x86_64__) || defined(_M_X64) +#define IS_X86 +#define IS_X86_64 +#endif + +#if defined(__i386__) || defined(_M_IX86) +#define IS_X86 +#define IS_X86_32 +#endif + +#if defined(IS_X86) +#if defined(_MSC_VER) +#include +#endif +#include +#endif + +#if defined(IS_X86) +#define MAX_SIMD_DEGREE 16 +#elif defined(BLAKE3_USE_NEON) +#define MAX_SIMD_DEGREE 4 +#else +#define MAX_SIMD_DEGREE 1 +#endif + +// There are some places where we want a static size that's equal to the +// MAX_SIMD_DEGREE, but also at least 2. +#define MAX_SIMD_DEGREE_OR_2 (MAX_SIMD_DEGREE > 2 ? MAX_SIMD_DEGREE : 2) + +static const uint32_t IV[8] = {0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, + 0xA54FF53AUL, 0x510E527FUL, 0x9B05688CUL, + 0x1F83D9ABUL, 0x5BE0CD19UL}; + +static const uint8_t MSG_SCHEDULE[7][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}, + {3, 4, 10, 12, 13, 2, 7, 14, 6, 5, 9, 0, 11, 15, 8, 1}, + {10, 7, 12, 9, 14, 3, 13, 15, 4, 0, 11, 2, 5, 8, 1, 6}, + {12, 13, 9, 11, 15, 10, 14, 8, 7, 2, 5, 3, 0, 1, 6, 4}, + {9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7}, + {11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13}, +}; + +/* Find index of the highest set bit */ +/* x is assumed to be nonzero. */ +static unsigned int highest_one(uint64_t x) { +#if defined(__GNUC__) || defined(__clang__) + return 63 ^ __builtin_clzll(x); +#elif defined(_MSC_VER) && defined(IS_X86_64) + unsigned long index; + _BitScanReverse64(&index, x); + return index; +#elif defined(_MSC_VER) && defined(IS_X86_32) + if(x >> 32) { + unsigned long index; + _BitScanReverse(&index, x >> 32); + return 32 + index; + } else { + unsigned long index; + _BitScanReverse(&index, x); + return index; + } +#else + unsigned int c = 0; + if(x & 0xffffffff00000000ULL) { x >>= 32; c += 32; } + if(x & 0x00000000ffff0000ULL) { x >>= 16; c += 16; } + if(x & 0x000000000000ff00ULL) { x >>= 8; c += 8; } + if(x & 0x00000000000000f0ULL) { x >>= 4; c += 4; } + if(x & 0x000000000000000cULL) { x >>= 2; c += 2; } + if(x & 0x0000000000000002ULL) { c += 1; } + return c; +#endif +} + +// Count the number of 1 bits. +INLINE unsigned int popcnt(uint64_t x) { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_popcountll(x); +#else + unsigned int count = 0; + while (x != 0) { + count += 1; + x &= x - 1; + } + return count; +#endif +} + +// Largest power of two less than or equal to x. As a special case, returns 1 +// when x is 0. +INLINE uint64_t round_down_to_power_of_2(uint64_t x) { + return 1ULL << highest_one(x | 1); +} + +INLINE uint32_t counter_low(uint64_t counter) { return (uint32_t)counter; } + +INLINE uint32_t counter_high(uint64_t counter) { + return (uint32_t)(counter >> 32); +} + +INLINE uint32_t load32(const void *src) { + 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); +} + +INLINE void load_key_words(const uint8_t key[BLAKE3_KEY_LEN], + uint32_t key_words[8]) { + key_words[0] = load32(&key[0 * 4]); + key_words[1] = load32(&key[1 * 4]); + key_words[2] = load32(&key[2 * 4]); + key_words[3] = load32(&key[3 * 4]); + key_words[4] = load32(&key[4 * 4]); + key_words[5] = load32(&key[5 * 4]); + key_words[6] = load32(&key[6 * 4]); + key_words[7] = load32(&key[7 * 4]); +} + +void blake3_compress_in_place(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags); + +void blake3_compress_xof(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags, + uint8_t out[64]); + +void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, uint8_t *out); + +size_t blake3_simd_degree(void); + + +// Declarations for implementation-specific functions. +void blake3_compress_in_place_portable(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags); + +void blake3_compress_xof_portable(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags, uint8_t out[64]); + +void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out); + +#if defined(IS_X86) +#if !defined(BLAKE3_NO_SSE41) +void blake3_compress_in_place_sse41(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags); +void blake3_compress_xof_sse41(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags, uint8_t out[64]); +void blake3_hash_many_sse41(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out); +#endif +#if !defined(BLAKE3_NO_AVX2) +void blake3_hash_many_avx2(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out); +#endif +#if !defined(BLAKE3_NO_AVX512) +void blake3_compress_in_place_avx512(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags); + +void blake3_compress_xof_avx512(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags, uint8_t out[64]); + +void blake3_hash_many_avx512(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out); +#endif +#endif + +#if defined(BLAKE3_USE_NEON) +void blake3_hash_many_neon(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out); +#endif + + +#endif /* BLAKE3_IMPL_H */ diff --git a/src/Native/libmultihash/blake3/blake3_neon.c b/src/Native/libmultihash/blake3/blake3_neon.c new file mode 100644 index 000000000..46691f526 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_neon.c @@ -0,0 +1,346 @@ +#include "blake3_impl.h" + +#include + +// TODO: This is probably incorrect for big-endian ARM. How should that work? +INLINE uint32x4_t loadu_128(const uint8_t src[16]) { + // vld1q_u32 has alignment requirements. Don't use it. + uint32x4_t x; + memcpy(&x, src, 16); + return x; +} + +INLINE void storeu_128(uint32x4_t src, uint8_t dest[16]) { + // vst1q_u32 has alignment requirements. Don't use it. + memcpy(dest, &src, 16); +} + +INLINE uint32x4_t add_128(uint32x4_t a, uint32x4_t b) { + return vaddq_u32(a, b); +} + +INLINE uint32x4_t xor_128(uint32x4_t a, uint32x4_t b) { + return veorq_u32(a, b); +} + +INLINE uint32x4_t set1_128(uint32_t x) { return vld1q_dup_u32(&x); } + +INLINE uint32x4_t set4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + uint32_t array[4] = {a, b, c, d}; + return vld1q_u32(array); +} + +INLINE uint32x4_t rot16_128(uint32x4_t x) { + return vorrq_u32(vshrq_n_u32(x, 16), vshlq_n_u32(x, 32 - 16)); +} + +INLINE uint32x4_t rot12_128(uint32x4_t x) { + return vorrq_u32(vshrq_n_u32(x, 12), vshlq_n_u32(x, 32 - 12)); +} + +INLINE uint32x4_t rot8_128(uint32x4_t x) { + return vorrq_u32(vshrq_n_u32(x, 8), vshlq_n_u32(x, 32 - 8)); +} + +INLINE uint32x4_t rot7_128(uint32x4_t x) { + return vorrq_u32(vshrq_n_u32(x, 7), vshlq_n_u32(x, 32 - 7)); +} + +// TODO: compress_neon + +// TODO: hash2_neon + +/* + * ---------------------------------------------------------------------------- + * hash4_neon + * ---------------------------------------------------------------------------- + */ + +INLINE void round_fn4(uint32x4_t v[16], uint32x4_t m[16], size_t r) { + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); + v[0] = add_128(v[0], v[4]); + v[1] = add_128(v[1], v[5]); + v[2] = add_128(v[2], v[6]); + v[3] = add_128(v[3], v[7]); + v[12] = xor_128(v[12], v[0]); + v[13] = xor_128(v[13], v[1]); + v[14] = xor_128(v[14], v[2]); + v[15] = xor_128(v[15], v[3]); + v[12] = rot16_128(v[12]); + v[13] = rot16_128(v[13]); + v[14] = rot16_128(v[14]); + v[15] = rot16_128(v[15]); + v[8] = add_128(v[8], v[12]); + v[9] = add_128(v[9], v[13]); + v[10] = add_128(v[10], v[14]); + v[11] = add_128(v[11], v[15]); + v[4] = xor_128(v[4], v[8]); + v[5] = xor_128(v[5], v[9]); + v[6] = xor_128(v[6], v[10]); + v[7] = xor_128(v[7], v[11]); + v[4] = rot12_128(v[4]); + v[5] = rot12_128(v[5]); + v[6] = rot12_128(v[6]); + v[7] = rot12_128(v[7]); + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); + v[0] = add_128(v[0], v[4]); + v[1] = add_128(v[1], v[5]); + v[2] = add_128(v[2], v[6]); + v[3] = add_128(v[3], v[7]); + v[12] = xor_128(v[12], v[0]); + v[13] = xor_128(v[13], v[1]); + v[14] = xor_128(v[14], v[2]); + v[15] = xor_128(v[15], v[3]); + v[12] = rot8_128(v[12]); + v[13] = rot8_128(v[13]); + v[14] = rot8_128(v[14]); + v[15] = rot8_128(v[15]); + v[8] = add_128(v[8], v[12]); + v[9] = add_128(v[9], v[13]); + v[10] = add_128(v[10], v[14]); + v[11] = add_128(v[11], v[15]); + v[4] = xor_128(v[4], v[8]); + v[5] = xor_128(v[5], v[9]); + v[6] = xor_128(v[6], v[10]); + v[7] = xor_128(v[7], v[11]); + v[4] = rot7_128(v[4]); + v[5] = rot7_128(v[5]); + v[6] = rot7_128(v[6]); + v[7] = rot7_128(v[7]); + + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); + v[0] = add_128(v[0], v[5]); + v[1] = add_128(v[1], v[6]); + v[2] = add_128(v[2], v[7]); + v[3] = add_128(v[3], v[4]); + v[15] = xor_128(v[15], v[0]); + v[12] = xor_128(v[12], v[1]); + v[13] = xor_128(v[13], v[2]); + v[14] = xor_128(v[14], v[3]); + v[15] = rot16_128(v[15]); + v[12] = rot16_128(v[12]); + v[13] = rot16_128(v[13]); + v[14] = rot16_128(v[14]); + v[10] = add_128(v[10], v[15]); + v[11] = add_128(v[11], v[12]); + v[8] = add_128(v[8], v[13]); + v[9] = add_128(v[9], v[14]); + v[5] = xor_128(v[5], v[10]); + v[6] = xor_128(v[6], v[11]); + v[7] = xor_128(v[7], v[8]); + v[4] = xor_128(v[4], v[9]); + v[5] = rot12_128(v[5]); + v[6] = rot12_128(v[6]); + v[7] = rot12_128(v[7]); + v[4] = rot12_128(v[4]); + v[0] = add_128(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); + v[1] = add_128(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); + v[2] = add_128(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); + v[3] = add_128(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); + v[0] = add_128(v[0], v[5]); + v[1] = add_128(v[1], v[6]); + v[2] = add_128(v[2], v[7]); + v[3] = add_128(v[3], v[4]); + v[15] = xor_128(v[15], v[0]); + v[12] = xor_128(v[12], v[1]); + v[13] = xor_128(v[13], v[2]); + v[14] = xor_128(v[14], v[3]); + v[15] = rot8_128(v[15]); + v[12] = rot8_128(v[12]); + v[13] = rot8_128(v[13]); + v[14] = rot8_128(v[14]); + v[10] = add_128(v[10], v[15]); + v[11] = add_128(v[11], v[12]); + v[8] = add_128(v[8], v[13]); + v[9] = add_128(v[9], v[14]); + v[5] = xor_128(v[5], v[10]); + v[6] = xor_128(v[6], v[11]); + v[7] = xor_128(v[7], v[8]); + v[4] = xor_128(v[4], v[9]); + v[5] = rot7_128(v[5]); + v[6] = rot7_128(v[6]); + v[7] = rot7_128(v[7]); + v[4] = rot7_128(v[4]); +} + +INLINE void transpose_vecs_128(uint32x4_t vecs[4]) { + // Individually transpose the four 2x2 sub-matrices in each corner. + uint32x4x2_t rows01 = vtrnq_u32(vecs[0], vecs[1]); + uint32x4x2_t rows23 = vtrnq_u32(vecs[2], vecs[3]); + + // Swap the top-right and bottom-left 2x2s (which just got transposed). + vecs[0] = + vcombine_u32(vget_low_u32(rows01.val[0]), vget_low_u32(rows23.val[0])); + vecs[1] = + vcombine_u32(vget_low_u32(rows01.val[1]), vget_low_u32(rows23.val[1])); + vecs[2] = + vcombine_u32(vget_high_u32(rows01.val[0]), vget_high_u32(rows23.val[0])); + vecs[3] = + vcombine_u32(vget_high_u32(rows01.val[1]), vget_high_u32(rows23.val[1])); +} + +INLINE void transpose_msg_vecs4(const uint8_t *const *inputs, + size_t block_offset, uint32x4_t out[16]) { + out[0] = loadu_128(&inputs[0][block_offset + 0 * sizeof(uint32x4_t)]); + out[1] = loadu_128(&inputs[1][block_offset + 0 * sizeof(uint32x4_t)]); + out[2] = loadu_128(&inputs[2][block_offset + 0 * sizeof(uint32x4_t)]); + out[3] = loadu_128(&inputs[3][block_offset + 0 * sizeof(uint32x4_t)]); + out[4] = loadu_128(&inputs[0][block_offset + 1 * sizeof(uint32x4_t)]); + out[5] = loadu_128(&inputs[1][block_offset + 1 * sizeof(uint32x4_t)]); + out[6] = loadu_128(&inputs[2][block_offset + 1 * sizeof(uint32x4_t)]); + out[7] = loadu_128(&inputs[3][block_offset + 1 * sizeof(uint32x4_t)]); + out[8] = loadu_128(&inputs[0][block_offset + 2 * sizeof(uint32x4_t)]); + out[9] = loadu_128(&inputs[1][block_offset + 2 * sizeof(uint32x4_t)]); + out[10] = loadu_128(&inputs[2][block_offset + 2 * sizeof(uint32x4_t)]); + out[11] = loadu_128(&inputs[3][block_offset + 2 * sizeof(uint32x4_t)]); + out[12] = loadu_128(&inputs[0][block_offset + 3 * sizeof(uint32x4_t)]); + out[13] = loadu_128(&inputs[1][block_offset + 3 * sizeof(uint32x4_t)]); + out[14] = loadu_128(&inputs[2][block_offset + 3 * sizeof(uint32x4_t)]); + out[15] = loadu_128(&inputs[3][block_offset + 3 * sizeof(uint32x4_t)]); + transpose_vecs_128(&out[0]); + transpose_vecs_128(&out[4]); + transpose_vecs_128(&out[8]); + transpose_vecs_128(&out[12]); +} + +INLINE void load_counters4(uint64_t counter, bool increment_counter, + uint32x4_t *out_low, uint32x4_t *out_high) { + uint64_t mask = (increment_counter ? ~0 : 0); + *out_low = set4( + counter_low(counter + (mask & 0)), counter_low(counter + (mask & 1)), + counter_low(counter + (mask & 2)), counter_low(counter + (mask & 3))); + *out_high = set4( + counter_high(counter + (mask & 0)), counter_high(counter + (mask & 1)), + counter_high(counter + (mask & 2)), counter_high(counter + (mask & 3))); +} + +void blake3_hash4_neon(const uint8_t *const *inputs, size_t blocks, + const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, uint8_t *out) { + uint32x4_t h_vecs[8] = { + set1_128(key[0]), set1_128(key[1]), set1_128(key[2]), set1_128(key[3]), + set1_128(key[4]), set1_128(key[5]), set1_128(key[6]), set1_128(key[7]), + }; + uint32x4_t counter_low_vec, counter_high_vec; + load_counters4(counter, increment_counter, &counter_low_vec, + &counter_high_vec); + uint8_t block_flags = flags | flags_start; + + for (size_t block = 0; block < blocks; block++) { + if (block + 1 == blocks) { + block_flags |= flags_end; + } + uint32x4_t block_len_vec = set1_128(BLAKE3_BLOCK_LEN); + uint32x4_t block_flags_vec = set1_128(block_flags); + uint32x4_t msg_vecs[16]; + transpose_msg_vecs4(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); + + uint32x4_t v[16] = { + h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], + h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], + set1_128(IV[0]), set1_128(IV[1]), set1_128(IV[2]), set1_128(IV[3]), + counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, + }; + round_fn4(v, msg_vecs, 0); + round_fn4(v, msg_vecs, 1); + round_fn4(v, msg_vecs, 2); + round_fn4(v, msg_vecs, 3); + round_fn4(v, msg_vecs, 4); + round_fn4(v, msg_vecs, 5); + round_fn4(v, msg_vecs, 6); + h_vecs[0] = xor_128(v[0], v[8]); + h_vecs[1] = xor_128(v[1], v[9]); + h_vecs[2] = xor_128(v[2], v[10]); + h_vecs[3] = xor_128(v[3], v[11]); + h_vecs[4] = xor_128(v[4], v[12]); + h_vecs[5] = xor_128(v[5], v[13]); + h_vecs[6] = xor_128(v[6], v[14]); + h_vecs[7] = xor_128(v[7], v[15]); + + block_flags = flags; + } + + transpose_vecs_128(&h_vecs[0]); + transpose_vecs_128(&h_vecs[4]); + // The first four vecs now contain the first half of each output, and the + // second four vecs contain the second half of each output. + storeu_128(h_vecs[0], &out[0 * sizeof(uint32x4_t)]); + storeu_128(h_vecs[4], &out[1 * sizeof(uint32x4_t)]); + storeu_128(h_vecs[1], &out[2 * sizeof(uint32x4_t)]); + storeu_128(h_vecs[5], &out[3 * sizeof(uint32x4_t)]); + storeu_128(h_vecs[2], &out[4 * sizeof(uint32x4_t)]); + storeu_128(h_vecs[6], &out[5 * sizeof(uint32x4_t)]); + storeu_128(h_vecs[3], &out[6 * sizeof(uint32x4_t)]); + storeu_128(h_vecs[7], &out[7 * sizeof(uint32x4_t)]); +} + +/* + * ---------------------------------------------------------------------------- + * hash_many_neon + * ---------------------------------------------------------------------------- + */ + +void blake3_compress_in_place_portable(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags); + +INLINE void hash_one_neon(const uint8_t *input, size_t blocks, + const uint32_t key[8], uint64_t counter, + uint8_t flags, uint8_t flags_start, uint8_t flags_end, + uint8_t out[BLAKE3_OUT_LEN]) { + uint32_t cv[8]; + memcpy(cv, key, BLAKE3_KEY_LEN); + uint8_t block_flags = flags | flags_start; + while (blocks > 0) { + if (blocks == 1) { + block_flags |= flags_end; + } + // TODO: Implement compress_neon. However note that according to + // https://github.com/BLAKE2/BLAKE2/commit/7965d3e6e1b4193438b8d3a656787587d2579227, + // compress_neon might not be any faster than compress_portable. + blake3_compress_in_place_portable(cv, input, BLAKE3_BLOCK_LEN, counter, + block_flags); + input = &input[BLAKE3_BLOCK_LEN]; + blocks -= 1; + block_flags = flags; + } + memcpy(out, cv, BLAKE3_OUT_LEN); +} + +void blake3_hash_many_neon(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out) { + while (num_inputs >= 4) { + blake3_hash4_neon(inputs, blocks, key, counter, increment_counter, flags, + flags_start, flags_end, out); + if (increment_counter) { + counter += 4; + } + inputs += 4; + num_inputs -= 4; + out = &out[4 * BLAKE3_OUT_LEN]; + } + while (num_inputs > 0) { + hash_one_neon(inputs[0], blocks, key, counter, flags, flags_start, + flags_end, out); + if (increment_counter) { + counter += 1; + } + inputs += 1; + num_inputs -= 1; + out = &out[BLAKE3_OUT_LEN]; + } +} diff --git a/src/Native/libmultihash/blake3/blake3_portable.c b/src/Native/libmultihash/blake3/blake3_portable.c new file mode 100644 index 000000000..9ee2f4a42 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_portable.c @@ -0,0 +1,168 @@ +#include "blake3_impl.h" +#include + +INLINE void store32(void *dst, uint32_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); +} + +INLINE uint32_t rotr32(uint32_t w, uint32_t c) { + return (w >> c) | (w << (32 - c)); +} + +INLINE void g(uint32_t *state, size_t a, size_t b, size_t c, size_t d, + uint32_t x, uint32_t y) { + state[a] = state[a] + state[b] + x; + state[d] = rotr32(state[d] ^ state[a], 16); + state[c] = state[c] + state[d]; + state[b] = rotr32(state[b] ^ state[c], 12); + state[a] = state[a] + state[b] + y; + state[d] = rotr32(state[d] ^ state[a], 8); + state[c] = state[c] + state[d]; + state[b] = rotr32(state[b] ^ state[c], 7); +} + +INLINE void round_fn(uint32_t state[16], const uint32_t *msg, size_t round) { + // Select the message schedule based on the round. + const uint8_t *schedule = MSG_SCHEDULE[round]; + + // Mix the columns. + g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]); + g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]); + g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]); + g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]); + + // Mix the rows. + g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]); + g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]); + g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]); + g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]); +} + +INLINE void compress_pre(uint32_t state[16], const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags) { + uint32_t block_words[16]; + block_words[0] = load32(block + 4 * 0); + block_words[1] = load32(block + 4 * 1); + block_words[2] = load32(block + 4 * 2); + block_words[3] = load32(block + 4 * 3); + block_words[4] = load32(block + 4 * 4); + block_words[5] = load32(block + 4 * 5); + block_words[6] = load32(block + 4 * 6); + block_words[7] = load32(block + 4 * 7); + block_words[8] = load32(block + 4 * 8); + block_words[9] = load32(block + 4 * 9); + block_words[10] = load32(block + 4 * 10); + block_words[11] = load32(block + 4 * 11); + block_words[12] = load32(block + 4 * 12); + block_words[13] = load32(block + 4 * 13); + block_words[14] = load32(block + 4 * 14); + block_words[15] = load32(block + 4 * 15); + + state[0] = cv[0]; + state[1] = cv[1]; + state[2] = cv[2]; + state[3] = cv[3]; + state[4] = cv[4]; + state[5] = cv[5]; + state[6] = cv[6]; + state[7] = cv[7]; + state[8] = IV[0]; + state[9] = IV[1]; + state[10] = IV[2]; + state[11] = IV[3]; + state[12] = counter_low(counter); + state[13] = counter_high(counter); + state[14] = (uint32_t)block_len; + state[15] = (uint32_t)flags; + + round_fn(state, &block_words[0], 0); + round_fn(state, &block_words[0], 1); + round_fn(state, &block_words[0], 2); + round_fn(state, &block_words[0], 3); + round_fn(state, &block_words[0], 4); + round_fn(state, &block_words[0], 5); + round_fn(state, &block_words[0], 6); +} + +void blake3_compress_in_place_portable(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags) { + uint32_t state[16]; + compress_pre(state, cv, block, block_len, counter, flags); + cv[0] = state[0] ^ state[8]; + cv[1] = state[1] ^ state[9]; + cv[2] = state[2] ^ state[10]; + cv[3] = state[3] ^ state[11]; + cv[4] = state[4] ^ state[12]; + cv[5] = state[5] ^ state[13]; + cv[6] = state[6] ^ state[14]; + cv[7] = state[7] ^ state[15]; +} + +void blake3_compress_xof_portable(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags, uint8_t out[64]) { + uint32_t state[16]; + compress_pre(state, cv, block, block_len, counter, flags); + + store32(&out[0 * 4], state[0] ^ state[8]); + store32(&out[1 * 4], state[1] ^ state[9]); + store32(&out[2 * 4], state[2] ^ state[10]); + store32(&out[3 * 4], state[3] ^ state[11]); + store32(&out[4 * 4], state[4] ^ state[12]); + store32(&out[5 * 4], state[5] ^ state[13]); + store32(&out[6 * 4], state[6] ^ state[14]); + store32(&out[7 * 4], state[7] ^ state[15]); + store32(&out[8 * 4], state[8] ^ cv[0]); + store32(&out[9 * 4], state[9] ^ cv[1]); + store32(&out[10 * 4], state[10] ^ cv[2]); + store32(&out[11 * 4], state[11] ^ cv[3]); + store32(&out[12 * 4], state[12] ^ cv[4]); + store32(&out[13 * 4], state[13] ^ cv[5]); + store32(&out[14 * 4], state[14] ^ cv[6]); + store32(&out[15 * 4], state[15] ^ cv[7]); +} + +INLINE void hash_one_portable(const uint8_t *input, size_t blocks, + const uint32_t key[8], uint64_t counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { + uint32_t cv[8]; + memcpy(cv, key, BLAKE3_KEY_LEN); + uint8_t block_flags = flags | flags_start; + while (blocks > 0) { + if (blocks == 1) { + block_flags |= flags_end; + } + blake3_compress_in_place_portable(cv, input, BLAKE3_BLOCK_LEN, counter, + block_flags); + input = &input[BLAKE3_BLOCK_LEN]; + blocks -= 1; + block_flags = flags; + } + memcpy(out, cv, 32); +} + +void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out) { + while (num_inputs > 0) { + hash_one_portable(inputs[0], blocks, key, counter, flags, flags_start, + flags_end, out); + if (increment_counter) { + counter += 1; + } + inputs += 1; + num_inputs -= 1; + out = &out[BLAKE3_OUT_LEN]; + } +} diff --git a/src/Native/libmultihash/blake3/blake3_sse41.c b/src/Native/libmultihash/blake3/blake3_sse41.c new file mode 100644 index 000000000..b31122533 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_sse41.c @@ -0,0 +1,559 @@ +#include "blake3_impl.h" + +#include + +#define DEGREE 4 + +#define _mm_shuffle_ps2(a, b, c) \ + (_mm_castps_si128( \ + _mm_shuffle_ps(_mm_castsi128_ps(a), _mm_castsi128_ps(b), (c)))) + +INLINE __m128i loadu(const uint8_t src[16]) { + return _mm_loadu_si128((const __m128i *)src); +} + +INLINE void storeu(__m128i src, uint8_t dest[16]) { + _mm_storeu_si128((__m128i *)dest, src); +} + +INLINE __m128i addv(__m128i a, __m128i b) { return _mm_add_epi32(a, b); } + +// Note that clang-format doesn't like the name "xor" for some reason. +INLINE __m128i xorv(__m128i a, __m128i b) { return _mm_xor_si128(a, b); } + +INLINE __m128i set1(uint32_t x) { return _mm_set1_epi32((int32_t)x); } + +INLINE __m128i set4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + return _mm_setr_epi32((int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d); +} + +INLINE __m128i rot16(__m128i x) { + return _mm_shuffle_epi8( + x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2)); +} + +INLINE __m128i rot12(__m128i x) { + return xorv(_mm_srli_epi32(x, 12), _mm_slli_epi32(x, 32 - 12)); +} + +INLINE __m128i rot8(__m128i x) { + return _mm_shuffle_epi8( + x, _mm_set_epi8(12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1)); +} + +INLINE __m128i rot7(__m128i x) { + return xorv(_mm_srli_epi32(x, 7), _mm_slli_epi32(x, 32 - 7)); +} + +INLINE void g1(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, + __m128i m) { + *row0 = addv(addv(*row0, m), *row1); + *row3 = xorv(*row3, *row0); + *row3 = rot16(*row3); + *row2 = addv(*row2, *row3); + *row1 = xorv(*row1, *row2); + *row1 = rot12(*row1); +} + +INLINE void g2(__m128i *row0, __m128i *row1, __m128i *row2, __m128i *row3, + __m128i m) { + *row0 = addv(addv(*row0, m), *row1); + *row3 = xorv(*row3, *row0); + *row3 = rot8(*row3); + *row2 = addv(*row2, *row3); + *row1 = xorv(*row1, *row2); + *row1 = rot7(*row1); +} + +// Note the optimization here of leaving row1 as the unrotated row, rather than +// row0. All the message loads below are adjusted to compensate for this. See +// discussion at https://github.com/sneves/blake2-avx2/pull/4 +INLINE void diagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { + *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(2, 1, 0, 3)); + *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); + *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(0, 3, 2, 1)); +} + +INLINE void undiagonalize(__m128i *row0, __m128i *row2, __m128i *row3) { + *row0 = _mm_shuffle_epi32(*row0, _MM_SHUFFLE(0, 3, 2, 1)); + *row3 = _mm_shuffle_epi32(*row3, _MM_SHUFFLE(1, 0, 3, 2)); + *row2 = _mm_shuffle_epi32(*row2, _MM_SHUFFLE(2, 1, 0, 3)); +} + +INLINE void compress_pre(__m128i rows[4], const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, uint8_t flags) { + rows[0] = loadu((uint8_t *)&cv[0]); + rows[1] = loadu((uint8_t *)&cv[4]); + rows[2] = set4(IV[0], IV[1], IV[2], IV[3]); + rows[3] = set4(counter_low(counter), counter_high(counter), + (uint32_t)block_len, (uint32_t)flags); + + __m128i m0 = loadu(&block[sizeof(__m128i) * 0]); + __m128i m1 = loadu(&block[sizeof(__m128i) * 1]); + __m128i m2 = loadu(&block[sizeof(__m128i) * 2]); + __m128i m3 = loadu(&block[sizeof(__m128i) * 3]); + + __m128i t0, t1, t2, t3, tt; + + // Round 1. The first round permutes the message words from the original + // input order, into the groups that get mixed in parallel. + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(2, 0, 2, 0)); // 6 4 2 0 + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 3, 1)); // 7 5 3 1 + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(2, 0, 2, 0)); // 14 12 10 8 + t2 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(2, 1, 0, 3)); // 12 10 8 14 + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 1, 3, 1)); // 15 13 11 9 + t3 = _mm_shuffle_epi32(t3, _MM_SHUFFLE(2, 1, 0, 3)); // 13 11 9 15 + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 2. This round and all following rounds apply a fixed permutation + // to the message words from the round before. + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 3 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 4 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 5 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 6 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); + m0 = t0; + m1 = t1; + m2 = t2; + m3 = t3; + + // Round 7 + t0 = _mm_shuffle_ps2(m0, m1, _MM_SHUFFLE(3, 1, 1, 2)); + t0 = _mm_shuffle_epi32(t0, _MM_SHUFFLE(0, 3, 2, 1)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t0); + t1 = _mm_shuffle_ps2(m2, m3, _MM_SHUFFLE(3, 3, 2, 2)); + tt = _mm_shuffle_epi32(m0, _MM_SHUFFLE(0, 0, 3, 3)); + t1 = _mm_blend_epi16(tt, t1, 0xCC); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t1); + diagonalize(&rows[0], &rows[2], &rows[3]); + t2 = _mm_unpacklo_epi64(m3, m1); + tt = _mm_blend_epi16(t2, m2, 0xC0); + t2 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(1, 3, 2, 0)); + g1(&rows[0], &rows[1], &rows[2], &rows[3], t2); + t3 = _mm_unpackhi_epi32(m1, m3); + tt = _mm_unpacklo_epi32(m2, t3); + t3 = _mm_shuffle_epi32(tt, _MM_SHUFFLE(0, 1, 3, 2)); + g2(&rows[0], &rows[1], &rows[2], &rows[3], t3); + undiagonalize(&rows[0], &rows[2], &rows[3]); +} + +void blake3_compress_in_place_sse41(uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags) { + __m128i rows[4]; + compress_pre(rows, cv, block, block_len, counter, flags); + storeu(xorv(rows[0], rows[2]), (uint8_t *)&cv[0]); + storeu(xorv(rows[1], rows[3]), (uint8_t *)&cv[4]); +} + +void blake3_compress_xof_sse41(const uint32_t cv[8], + const uint8_t block[BLAKE3_BLOCK_LEN], + uint8_t block_len, uint64_t counter, + uint8_t flags, uint8_t out[64]) { + __m128i rows[4]; + compress_pre(rows, cv, block, block_len, counter, flags); + storeu(xorv(rows[0], rows[2]), &out[0]); + storeu(xorv(rows[1], rows[3]), &out[16]); + storeu(xorv(rows[2], loadu((uint8_t *)&cv[0])), &out[32]); + storeu(xorv(rows[3], loadu((uint8_t *)&cv[4])), &out[48]); +} + +INLINE void round_fn(__m128i v[16], __m128i m[16], size_t r) { + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][0]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][2]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][4]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][6]]); + v[0] = addv(v[0], v[4]); + v[1] = addv(v[1], v[5]); + v[2] = addv(v[2], v[6]); + v[3] = addv(v[3], v[7]); + v[12] = xorv(v[12], v[0]); + v[13] = xorv(v[13], v[1]); + v[14] = xorv(v[14], v[2]); + v[15] = xorv(v[15], v[3]); + v[12] = rot16(v[12]); + v[13] = rot16(v[13]); + v[14] = rot16(v[14]); + v[15] = rot16(v[15]); + v[8] = addv(v[8], v[12]); + v[9] = addv(v[9], v[13]); + v[10] = addv(v[10], v[14]); + v[11] = addv(v[11], v[15]); + v[4] = xorv(v[4], v[8]); + v[5] = xorv(v[5], v[9]); + v[6] = xorv(v[6], v[10]); + v[7] = xorv(v[7], v[11]); + v[4] = rot12(v[4]); + v[5] = rot12(v[5]); + v[6] = rot12(v[6]); + v[7] = rot12(v[7]); + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][1]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][3]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][5]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][7]]); + v[0] = addv(v[0], v[4]); + v[1] = addv(v[1], v[5]); + v[2] = addv(v[2], v[6]); + v[3] = addv(v[3], v[7]); + v[12] = xorv(v[12], v[0]); + v[13] = xorv(v[13], v[1]); + v[14] = xorv(v[14], v[2]); + v[15] = xorv(v[15], v[3]); + v[12] = rot8(v[12]); + v[13] = rot8(v[13]); + v[14] = rot8(v[14]); + v[15] = rot8(v[15]); + v[8] = addv(v[8], v[12]); + v[9] = addv(v[9], v[13]); + v[10] = addv(v[10], v[14]); + v[11] = addv(v[11], v[15]); + v[4] = xorv(v[4], v[8]); + v[5] = xorv(v[5], v[9]); + v[6] = xorv(v[6], v[10]); + v[7] = xorv(v[7], v[11]); + v[4] = rot7(v[4]); + v[5] = rot7(v[5]); + v[6] = rot7(v[6]); + v[7] = rot7(v[7]); + + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][8]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][10]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][12]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][14]]); + v[0] = addv(v[0], v[5]); + v[1] = addv(v[1], v[6]); + v[2] = addv(v[2], v[7]); + v[3] = addv(v[3], v[4]); + v[15] = xorv(v[15], v[0]); + v[12] = xorv(v[12], v[1]); + v[13] = xorv(v[13], v[2]); + v[14] = xorv(v[14], v[3]); + v[15] = rot16(v[15]); + v[12] = rot16(v[12]); + v[13] = rot16(v[13]); + v[14] = rot16(v[14]); + v[10] = addv(v[10], v[15]); + v[11] = addv(v[11], v[12]); + v[8] = addv(v[8], v[13]); + v[9] = addv(v[9], v[14]); + v[5] = xorv(v[5], v[10]); + v[6] = xorv(v[6], v[11]); + v[7] = xorv(v[7], v[8]); + v[4] = xorv(v[4], v[9]); + v[5] = rot12(v[5]); + v[6] = rot12(v[6]); + v[7] = rot12(v[7]); + v[4] = rot12(v[4]); + v[0] = addv(v[0], m[(size_t)MSG_SCHEDULE[r][9]]); + v[1] = addv(v[1], m[(size_t)MSG_SCHEDULE[r][11]]); + v[2] = addv(v[2], m[(size_t)MSG_SCHEDULE[r][13]]); + v[3] = addv(v[3], m[(size_t)MSG_SCHEDULE[r][15]]); + v[0] = addv(v[0], v[5]); + v[1] = addv(v[1], v[6]); + v[2] = addv(v[2], v[7]); + v[3] = addv(v[3], v[4]); + v[15] = xorv(v[15], v[0]); + v[12] = xorv(v[12], v[1]); + v[13] = xorv(v[13], v[2]); + v[14] = xorv(v[14], v[3]); + v[15] = rot8(v[15]); + v[12] = rot8(v[12]); + v[13] = rot8(v[13]); + v[14] = rot8(v[14]); + v[10] = addv(v[10], v[15]); + v[11] = addv(v[11], v[12]); + v[8] = addv(v[8], v[13]); + v[9] = addv(v[9], v[14]); + v[5] = xorv(v[5], v[10]); + v[6] = xorv(v[6], v[11]); + v[7] = xorv(v[7], v[8]); + v[4] = xorv(v[4], v[9]); + v[5] = rot7(v[5]); + v[6] = rot7(v[6]); + v[7] = rot7(v[7]); + v[4] = rot7(v[4]); +} + +INLINE void transpose_vecs(__m128i vecs[DEGREE]) { + // Interleave 32-bit lates. The low unpack is lanes 00/11 and the high is + // 22/33. Note that this doesn't split the vector into two lanes, as the + // AVX2 counterparts do. + __m128i ab_01 = _mm_unpacklo_epi32(vecs[0], vecs[1]); + __m128i ab_23 = _mm_unpackhi_epi32(vecs[0], vecs[1]); + __m128i cd_01 = _mm_unpacklo_epi32(vecs[2], vecs[3]); + __m128i cd_23 = _mm_unpackhi_epi32(vecs[2], vecs[3]); + + // Interleave 64-bit lanes. + __m128i abcd_0 = _mm_unpacklo_epi64(ab_01, cd_01); + __m128i abcd_1 = _mm_unpackhi_epi64(ab_01, cd_01); + __m128i abcd_2 = _mm_unpacklo_epi64(ab_23, cd_23); + __m128i abcd_3 = _mm_unpackhi_epi64(ab_23, cd_23); + + vecs[0] = abcd_0; + vecs[1] = abcd_1; + vecs[2] = abcd_2; + vecs[3] = abcd_3; +} + +INLINE void transpose_msg_vecs(const uint8_t *const *inputs, + size_t block_offset, __m128i out[16]) { + out[0] = loadu(&inputs[0][block_offset + 0 * sizeof(__m128i)]); + out[1] = loadu(&inputs[1][block_offset + 0 * sizeof(__m128i)]); + out[2] = loadu(&inputs[2][block_offset + 0 * sizeof(__m128i)]); + out[3] = loadu(&inputs[3][block_offset + 0 * sizeof(__m128i)]); + out[4] = loadu(&inputs[0][block_offset + 1 * sizeof(__m128i)]); + out[5] = loadu(&inputs[1][block_offset + 1 * sizeof(__m128i)]); + out[6] = loadu(&inputs[2][block_offset + 1 * sizeof(__m128i)]); + out[7] = loadu(&inputs[3][block_offset + 1 * sizeof(__m128i)]); + out[8] = loadu(&inputs[0][block_offset + 2 * sizeof(__m128i)]); + out[9] = loadu(&inputs[1][block_offset + 2 * sizeof(__m128i)]); + out[10] = loadu(&inputs[2][block_offset + 2 * sizeof(__m128i)]); + out[11] = loadu(&inputs[3][block_offset + 2 * sizeof(__m128i)]); + out[12] = loadu(&inputs[0][block_offset + 3 * sizeof(__m128i)]); + out[13] = loadu(&inputs[1][block_offset + 3 * sizeof(__m128i)]); + out[14] = loadu(&inputs[2][block_offset + 3 * sizeof(__m128i)]); + out[15] = loadu(&inputs[3][block_offset + 3 * sizeof(__m128i)]); + for (size_t i = 0; i < 4; ++i) { + _mm_prefetch(&inputs[i][block_offset + 256], _MM_HINT_T0); + } + transpose_vecs(&out[0]); + transpose_vecs(&out[4]); + transpose_vecs(&out[8]); + transpose_vecs(&out[12]); +} + +INLINE void load_counters(uint64_t counter, bool increment_counter, + __m128i *out_lo, __m128i *out_hi) { + const __m128i mask = _mm_set1_epi32(-(int32_t)increment_counter); + const __m128i add0 = _mm_set_epi32(3, 2, 1, 0); + const __m128i add1 = _mm_and_si128(mask, add0); + __m128i l = _mm_add_epi32(_mm_set1_epi32(counter), add1); + __m128i carry = _mm_cmpgt_epi32(_mm_xor_si128(add1, _mm_set1_epi32(0x80000000)), + _mm_xor_si128( l, _mm_set1_epi32(0x80000000))); + __m128i h = _mm_sub_epi32(_mm_set1_epi32(counter >> 32), carry); + *out_lo = l; + *out_hi = h; +} + +void blake3_hash4_sse41(const uint8_t *const *inputs, size_t blocks, + const uint32_t key[8], uint64_t counter, + bool increment_counter, uint8_t flags, + uint8_t flags_start, uint8_t flags_end, uint8_t *out) { + __m128i h_vecs[8] = { + set1(key[0]), set1(key[1]), set1(key[2]), set1(key[3]), + set1(key[4]), set1(key[5]), set1(key[6]), set1(key[7]), + }; + __m128i counter_low_vec, counter_high_vec; + load_counters(counter, increment_counter, &counter_low_vec, + &counter_high_vec); + uint8_t block_flags = flags | flags_start; + + for (size_t block = 0; block < blocks; block++) { + if (block + 1 == blocks) { + block_flags |= flags_end; + } + __m128i block_len_vec = set1(BLAKE3_BLOCK_LEN); + __m128i block_flags_vec = set1(block_flags); + __m128i msg_vecs[16]; + transpose_msg_vecs(inputs, block * BLAKE3_BLOCK_LEN, msg_vecs); + + __m128i v[16] = { + h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3], + h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7], + set1(IV[0]), set1(IV[1]), set1(IV[2]), set1(IV[3]), + counter_low_vec, counter_high_vec, block_len_vec, block_flags_vec, + }; + round_fn(v, msg_vecs, 0); + round_fn(v, msg_vecs, 1); + round_fn(v, msg_vecs, 2); + round_fn(v, msg_vecs, 3); + round_fn(v, msg_vecs, 4); + round_fn(v, msg_vecs, 5); + round_fn(v, msg_vecs, 6); + h_vecs[0] = xorv(v[0], v[8]); + h_vecs[1] = xorv(v[1], v[9]); + h_vecs[2] = xorv(v[2], v[10]); + h_vecs[3] = xorv(v[3], v[11]); + h_vecs[4] = xorv(v[4], v[12]); + h_vecs[5] = xorv(v[5], v[13]); + h_vecs[6] = xorv(v[6], v[14]); + h_vecs[7] = xorv(v[7], v[15]); + + block_flags = flags; + } + + transpose_vecs(&h_vecs[0]); + transpose_vecs(&h_vecs[4]); + // The first four vecs now contain the first half of each output, and the + // second four vecs contain the second half of each output. + storeu(h_vecs[0], &out[0 * sizeof(__m128i)]); + storeu(h_vecs[4], &out[1 * sizeof(__m128i)]); + storeu(h_vecs[1], &out[2 * sizeof(__m128i)]); + storeu(h_vecs[5], &out[3 * sizeof(__m128i)]); + storeu(h_vecs[2], &out[4 * sizeof(__m128i)]); + storeu(h_vecs[6], &out[5 * sizeof(__m128i)]); + storeu(h_vecs[3], &out[6 * sizeof(__m128i)]); + storeu(h_vecs[7], &out[7 * sizeof(__m128i)]); +} + +INLINE void hash_one_sse41(const uint8_t *input, size_t blocks, + const uint32_t key[8], uint64_t counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { + uint32_t cv[8]; + memcpy(cv, key, BLAKE3_KEY_LEN); + uint8_t block_flags = flags | flags_start; + while (blocks > 0) { + if (blocks == 1) { + block_flags |= flags_end; + } + blake3_compress_in_place_sse41(cv, input, BLAKE3_BLOCK_LEN, counter, + block_flags); + input = &input[BLAKE3_BLOCK_LEN]; + blocks -= 1; + block_flags = flags; + } + memcpy(out, cv, BLAKE3_OUT_LEN); +} + +void blake3_hash_many_sse41(const uint8_t *const *inputs, size_t num_inputs, + size_t blocks, const uint32_t key[8], + uint64_t counter, bool increment_counter, + uint8_t flags, uint8_t flags_start, + uint8_t flags_end, uint8_t *out) { + while (num_inputs >= DEGREE) { + blake3_hash4_sse41(inputs, blocks, key, counter, increment_counter, flags, + flags_start, flags_end, out); + if (increment_counter) { + counter += DEGREE; + } + inputs += DEGREE; + num_inputs -= DEGREE; + out = &out[DEGREE * BLAKE3_OUT_LEN]; + } + while (num_inputs > 0) { + hash_one_sse41(inputs[0], blocks, key, counter, flags, flags_start, + flags_end, out); + if (increment_counter) { + counter += 1; + } + inputs += 1; + num_inputs -= 1; + out = &out[BLAKE3_OUT_LEN]; + } +} diff --git a/src/Native/libmultihash/blake3/blake3_sse41_x86-64_unix.S b/src/Native/libmultihash/blake3/blake3_sse41_x86-64_unix.S new file mode 100644 index 000000000..41a1eb252 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_sse41_x86-64_unix.S @@ -0,0 +1,2024 @@ +#if defined(__ELF__) && defined(__CET__) && defined(__has_include) +#if __has_include() +#include +#endif +#endif + +#if !defined(_CET_ENDBR) +#define _CET_ENDBR +#endif + +.intel_syntax noprefix +.global blake3_hash_many_sse41 +.global _blake3_hash_many_sse41 +.global blake3_compress_in_place_sse41 +.global _blake3_compress_in_place_sse41 +.global blake3_compress_xof_sse41 +.global _blake3_compress_xof_sse41 +#ifdef __APPLE__ +.text +#else +.section .text +#endif + .p2align 6 +_blake3_hash_many_sse41: +blake3_hash_many_sse41: + _CET_ENDBR + push r15 + push r14 + push r13 + push r12 + push rbx + push rbp + mov rbp, rsp + sub rsp, 360 + and rsp, 0xFFFFFFFFFFFFFFC0 + neg r9d + movd xmm0, r9d + pshufd xmm0, xmm0, 0x00 + movdqa xmmword ptr [rsp+0x130], xmm0 + movdqa xmm1, xmm0 + pand xmm1, xmmword ptr [ADD0+rip] + pand xmm0, xmmword ptr [ADD1+rip] + movdqa xmmword ptr [rsp+0x150], xmm0 + movd xmm0, r8d + pshufd xmm0, xmm0, 0x00 + paddd xmm0, xmm1 + movdqa xmmword ptr [rsp+0x110], xmm0 + pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] + pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] + pcmpgtd xmm1, xmm0 + shr r8, 32 + movd xmm2, r8d + pshufd xmm2, xmm2, 0x00 + psubd xmm2, xmm1 + movdqa xmmword ptr [rsp+0x120], xmm2 + mov rbx, qword ptr [rbp+0x50] + mov r15, rdx + shl r15, 6 + movzx r13d, byte ptr [rbp+0x38] + movzx r12d, byte ptr [rbp+0x48] + cmp rsi, 4 + jc 3f +2: + movdqu xmm3, xmmword ptr [rcx] + pshufd xmm0, xmm3, 0x00 + pshufd xmm1, xmm3, 0x55 + pshufd xmm2, xmm3, 0xAA + pshufd xmm3, xmm3, 0xFF + movdqu xmm7, xmmword ptr [rcx+0x10] + pshufd xmm4, xmm7, 0x00 + pshufd xmm5, xmm7, 0x55 + pshufd xmm6, xmm7, 0xAA + pshufd xmm7, xmm7, 0xFF + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +9: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movdqu xmm8, xmmword ptr [r8+rdx-0x40] + movdqu xmm9, xmmword ptr [r9+rdx-0x40] + movdqu xmm10, xmmword ptr [r10+rdx-0x40] + movdqu xmm11, xmmword ptr [r11+rdx-0x40] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp], xmm8 + movdqa xmmword ptr [rsp+0x10], xmm9 + movdqa xmmword ptr [rsp+0x20], xmm12 + movdqa xmmword ptr [rsp+0x30], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-0x30] + movdqu xmm9, xmmword ptr [r9+rdx-0x30] + movdqu xmm10, xmmword ptr [r10+rdx-0x30] + movdqu xmm11, xmmword ptr [r11+rdx-0x30] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+0x40], xmm8 + movdqa xmmword ptr [rsp+0x50], xmm9 + movdqa xmmword ptr [rsp+0x60], xmm12 + movdqa xmmword ptr [rsp+0x70], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-0x20] + movdqu xmm9, xmmword ptr [r9+rdx-0x20] + movdqu xmm10, xmmword ptr [r10+rdx-0x20] + movdqu xmm11, xmmword ptr [r11+rdx-0x20] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+0x80], xmm8 + movdqa xmmword ptr [rsp+0x90], xmm9 + movdqa xmmword ptr [rsp+0xA0], xmm12 + movdqa xmmword ptr [rsp+0xB0], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-0x10] + movdqu xmm9, xmmword ptr [r9+rdx-0x10] + movdqu xmm10, xmmword ptr [r10+rdx-0x10] + movdqu xmm11, xmmword ptr [r11+rdx-0x10] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+0xC0], xmm8 + movdqa xmmword ptr [rsp+0xD0], xmm9 + movdqa xmmword ptr [rsp+0xE0], xmm12 + movdqa xmmword ptr [rsp+0xF0], xmm13 + movdqa xmm9, xmmword ptr [BLAKE3_IV_1+rip] + movdqa xmm10, xmmword ptr [BLAKE3_IV_2+rip] + movdqa xmm11, xmmword ptr [BLAKE3_IV_3+rip] + movdqa xmm12, xmmword ptr [rsp+0x110] + movdqa xmm13, xmmword ptr [rsp+0x120] + movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN+rip] + movd xmm15, eax + pshufd xmm15, xmm15, 0x00 + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + paddd xmm0, xmmword ptr [rsp] + paddd xmm1, xmmword ptr [rsp+0x20] + paddd xmm2, xmmword ptr [rsp+0x40] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [BLAKE3_IV_0+rip] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x10] + paddd xmm1, xmmword ptr [rsp+0x30] + paddd xmm2, xmmword ptr [rsp+0x50] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x80] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp+0xC0] + paddd xmm3, xmmword ptr [rsp+0xE0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x90] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0xD0] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x20] + paddd xmm1, xmmword ptr [rsp+0x30] + paddd xmm2, xmmword ptr [rsp+0x70] + paddd xmm3, xmmword ptr [rsp+0x40] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x60] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp] + paddd xmm3, xmmword ptr [rsp+0xD0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x10] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0x90] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xB0] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp+0xE0] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x30] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp+0xD0] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x40] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0x20] + paddd xmm3, xmmword ptr [rsp+0xE0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x60] + paddd xmm1, xmmword ptr [rsp+0x90] + paddd xmm2, xmmword ptr [rsp+0xB0] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x50] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+0xF0] + paddd xmm3, xmmword ptr [rsp+0x10] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xA0] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0xE0] + paddd xmm3, xmmword ptr [rsp+0xD0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x70] + paddd xmm1, xmmword ptr [rsp+0x90] + paddd xmm2, xmmword ptr [rsp+0x30] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x40] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0x50] + paddd xmm3, xmmword ptr [rsp+0x10] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp] + paddd xmm1, xmmword ptr [rsp+0x20] + paddd xmm2, xmmword ptr [rsp+0x80] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xC0] + paddd xmm1, xmmword ptr [rsp+0x90] + paddd xmm2, xmmword ptr [rsp+0xF0] + paddd xmm3, xmmword ptr [rsp+0xE0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xD0] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0xA0] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x70] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x20] + paddd xmm1, xmmword ptr [rsp+0x30] + paddd xmm2, xmmword ptr [rsp+0x10] + paddd xmm3, xmmword ptr [rsp+0x40] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x90] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0x80] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xE0] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp+0xC0] + paddd xmm3, xmmword ptr [rsp+0x10] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xD0] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+0x20] + paddd xmm3, xmmword ptr [rsp+0x40] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x30] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp+0x60] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xB0] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp+0x10] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xF0] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+0x90] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xE0] + paddd xmm1, xmmword ptr [rsp+0x20] + paddd xmm2, xmmword ptr [rsp+0x30] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xA0] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0x40] + paddd xmm3, xmmword ptr [rsp+0xD0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + pxor xmm0, xmm8 + pxor xmm1, xmm9 + pxor xmm2, xmm10 + pxor xmm3, xmm11 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + pxor xmm4, xmm12 + pxor xmm5, xmm13 + pxor xmm6, xmm14 + pxor xmm7, xmm15 + mov eax, r13d + jne 9b + movdqa xmm9, xmm0 + punpckldq xmm0, xmm1 + punpckhdq xmm9, xmm1 + movdqa xmm11, xmm2 + punpckldq xmm2, xmm3 + punpckhdq xmm11, xmm3 + movdqa xmm1, xmm0 + punpcklqdq xmm0, xmm2 + punpckhqdq xmm1, xmm2 + movdqa xmm3, xmm9 + punpcklqdq xmm9, xmm11 + punpckhqdq xmm3, xmm11 + movdqu xmmword ptr [rbx], xmm0 + movdqu xmmword ptr [rbx+0x20], xmm1 + movdqu xmmword ptr [rbx+0x40], xmm9 + movdqu xmmword ptr [rbx+0x60], xmm3 + movdqa xmm9, xmm4 + punpckldq xmm4, xmm5 + punpckhdq xmm9, xmm5 + movdqa xmm11, xmm6 + punpckldq xmm6, xmm7 + punpckhdq xmm11, xmm7 + movdqa xmm5, xmm4 + punpcklqdq xmm4, xmm6 + punpckhqdq xmm5, xmm6 + movdqa xmm7, xmm9 + punpcklqdq xmm9, xmm11 + punpckhqdq xmm7, xmm11 + movdqu xmmword ptr [rbx+0x10], xmm4 + movdqu xmmword ptr [rbx+0x30], xmm5 + movdqu xmmword ptr [rbx+0x50], xmm9 + movdqu xmmword ptr [rbx+0x70], xmm7 + movdqa xmm1, xmmword ptr [rsp+0x110] + movdqa xmm0, xmm1 + paddd xmm1, xmmword ptr [rsp+0x150] + movdqa xmmword ptr [rsp+0x110], xmm1 + pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] + pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] + pcmpgtd xmm0, xmm1 + movdqa xmm1, xmmword ptr [rsp+0x120] + psubd xmm1, xmm0 + movdqa xmmword ptr [rsp+0x120], xmm1 + add rbx, 128 + add rdi, 32 + sub rsi, 4 + cmp rsi, 4 + jnc 2b + test rsi, rsi + jnz 3f +4: + mov rsp, rbp + pop rbp + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + ret +.p2align 5 +3: + test esi, 0x2 + je 3f + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+0x10] + movaps xmm8, xmm0 + movaps xmm9, xmm1 + movd xmm13, dword ptr [rsp+0x110] + pinsrd xmm13, dword ptr [rsp+0x120], 1 + pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + movaps xmmword ptr [rsp], xmm13 + movd xmm14, dword ptr [rsp+0x114] + pinsrd xmm14, dword ptr [rsp+0x124], 1 + pinsrd xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + movaps xmmword ptr [rsp+0x10], xmm14 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + movaps xmm10, xmm2 + movups xmm4, xmmword ptr [r8+rdx-0x40] + movups xmm5, xmmword ptr [r8+rdx-0x30] + movaps xmm3, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm3, xmm5, 221 + movaps xmm5, xmm3 + movups xmm6, xmmword ptr [r8+rdx-0x20] + movups xmm7, xmmword ptr [r8+rdx-0x10] + movaps xmm3, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm3, xmm7, 221 + pshufd xmm7, xmm3, 0x93 + movups xmm12, xmmword ptr [r9+rdx-0x40] + movups xmm13, xmmword ptr [r9+rdx-0x30] + movaps xmm11, xmm12 + shufps xmm12, xmm13, 136 + shufps xmm11, xmm13, 221 + movaps xmm13, xmm11 + movups xmm14, xmmword ptr [r9+rdx-0x20] + movups xmm15, xmmword ptr [r9+rdx-0x10] + movaps xmm11, xmm14 + shufps xmm14, xmm15, 136 + pshufd xmm14, xmm14, 0x93 + shufps xmm11, xmm15, 221 + pshufd xmm15, xmm11, 0x93 + movaps xmm3, xmmword ptr [rsp] + movaps xmm11, xmmword ptr [rsp+0x10] + pinsrd xmm3, eax, 3 + pinsrd xmm11, eax, 3 + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm8, xmm12 + movaps xmmword ptr [rsp+0x20], xmm4 + movaps xmmword ptr [rsp+0x30], xmm12 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + movaps xmm12, xmmword ptr [ROT16+rip] + pshufb xmm3, xmm12 + pshufb xmm11, xmm12 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 20 + psrld xmm4, 12 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 20 + psrld xmm4, 12 + por xmm9, xmm4 + paddd xmm0, xmm5 + paddd xmm8, xmm13 + movaps xmmword ptr [rsp+0x40], xmm5 + movaps xmmword ptr [rsp+0x50], xmm13 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + movaps xmm13, xmmword ptr [ROT8+rip] + pshufb xmm3, xmm13 + pshufb xmm11, xmm13 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 25 + psrld xmm4, 7 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 25 + psrld xmm4, 7 + por xmm9, xmm4 + pshufd xmm0, xmm0, 0x93 + pshufd xmm8, xmm8, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm11, xmm11, 0x4E + pshufd xmm2, xmm2, 0x39 + pshufd xmm10, xmm10, 0x39 + paddd xmm0, xmm6 + paddd xmm8, xmm14 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + pshufb xmm3, xmm12 + pshufb xmm11, xmm12 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 20 + psrld xmm4, 12 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 20 + psrld xmm4, 12 + por xmm9, xmm4 + paddd xmm0, xmm7 + paddd xmm8, xmm15 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + pshufb xmm3, xmm13 + pshufb xmm11, xmm13 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 25 + psrld xmm4, 7 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 25 + psrld xmm4, 7 + por xmm9, xmm4 + pshufd xmm0, xmm0, 0x39 + pshufd xmm8, xmm8, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm11, xmm11, 0x4E + pshufd xmm2, xmm2, 0x93 + pshufd xmm10, xmm10, 0x93 + dec al + je 9f + movdqa xmm12, xmmword ptr [rsp+0x20] + movdqa xmm5, xmmword ptr [rsp+0x40] + pshufd xmm13, xmm12, 0x0F + shufps xmm12, xmm5, 214 + pshufd xmm4, xmm12, 0x39 + movdqa xmm12, xmm6 + shufps xmm12, xmm7, 250 + pblendw xmm13, xmm12, 0xCC + movdqa xmm12, xmm7 + punpcklqdq xmm12, xmm5 + pblendw xmm12, xmm6, 0xC0 + pshufd xmm12, xmm12, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmmword ptr [rsp+0x20], xmm13 + movdqa xmmword ptr [rsp+0x40], xmm12 + movdqa xmm5, xmmword ptr [rsp+0x30] + movdqa xmm13, xmmword ptr [rsp+0x50] + pshufd xmm6, xmm5, 0x0F + shufps xmm5, xmm13, 214 + pshufd xmm12, xmm5, 0x39 + movdqa xmm5, xmm14 + shufps xmm5, xmm15, 250 + pblendw xmm6, xmm5, 0xCC + movdqa xmm5, xmm15 + punpcklqdq xmm5, xmm13 + pblendw xmm5, xmm14, 0xC0 + pshufd xmm5, xmm5, 0x78 + punpckhdq xmm13, xmm15 + punpckldq xmm14, xmm13 + pshufd xmm15, xmm14, 0x1E + movdqa xmm13, xmm6 + movdqa xmm14, xmm5 + movdqa xmm5, xmmword ptr [rsp+0x20] + movdqa xmm6, xmmword ptr [rsp+0x40] + jmp 9b +9: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + pxor xmm8, xmm10 + pxor xmm9, xmm11 + mov eax, r13d + cmp rdx, r15 + jne 2b + movups xmmword ptr [rbx], xmm0 + movups xmmword ptr [rbx+0x10], xmm1 + movups xmmword ptr [rbx+0x20], xmm8 + movups xmmword ptr [rbx+0x30], xmm9 + movdqa xmm0, xmmword ptr [rsp+0x130] + movdqa xmm1, xmmword ptr [rsp+0x110] + movdqa xmm2, xmmword ptr [rsp+0x120] + movdqu xmm3, xmmword ptr [rsp+0x118] + movdqu xmm4, xmmword ptr [rsp+0x128] + blendvps xmm1, xmm3, xmm0 + blendvps xmm2, xmm4, xmm0 + movdqa xmmword ptr [rsp+0x110], xmm1 + movdqa xmmword ptr [rsp+0x120], xmm2 + add rdi, 16 + add rbx, 64 + sub rsi, 2 +3: + test esi, 0x1 + je 4b + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+0x10] + movd xmm13, dword ptr [rsp+0x110] + pinsrd xmm13, dword ptr [rsp+0x120], 1 + pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + movaps xmm14, xmmword ptr [ROT8+rip] + movaps xmm15, xmmword ptr [ROT16+rip] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+0x40] + or eax, r13d + xor edx, edx +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + movaps xmm3, xmm13 + pinsrd xmm3, eax, 3 + movups xmm4, xmmword ptr [r8+rdx-0x40] + movups xmm5, xmmword ptr [r8+rdx-0x30] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [r8+rdx-0x20] + movups xmm7, xmmword ptr [r8+rdx-0x10] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 0x93 + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x39 + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x93 + dec al + jz 9f + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0x0F + pshufd xmm4, xmm8, 0x39 + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0xCC + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0xC0 + pshufd xmm8, xmm8, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp 9b +9: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + movups xmmword ptr [rbx], xmm0 + movups xmmword ptr [rbx+0x10], xmm1 + jmp 4b + +.p2align 6 +blake3_compress_in_place_sse41: +_blake3_compress_in_place_sse41: + _CET_ENDBR + movups xmm0, xmmword ptr [rdi] + movups xmm1, xmmword ptr [rdi+0x10] + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + shl r8, 32 + add rdx, r8 + movq xmm3, rcx + movq xmm4, rdx + punpcklqdq xmm3, xmm4 + movups xmm4, xmmword ptr [rsi] + movups xmm5, xmmword ptr [rsi+0x10] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [rsi+0x20] + movups xmm7, xmmword ptr [rsi+0x30] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 0x93 + movaps xmm14, xmmword ptr [ROT8+rip] + movaps xmm15, xmmword ptr [ROT16+rip] + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x39 + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x93 + dec al + jz 9f + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0x0F + pshufd xmm4, xmm8, 0x39 + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0xCC + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0xC0 + pshufd xmm8, xmm8, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp 9b +9: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + movups xmmword ptr [rdi], xmm0 + movups xmmword ptr [rdi+0x10], xmm1 + ret + +.p2align 6 +blake3_compress_xof_sse41: +_blake3_compress_xof_sse41: + _CET_ENDBR + movups xmm0, xmmword ptr [rdi] + movups xmm1, xmmword ptr [rdi+0x10] + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + movzx eax, r8b + movzx edx, dl + shl rax, 32 + add rdx, rax + movq xmm3, rcx + movq xmm4, rdx + punpcklqdq xmm3, xmm4 + movups xmm4, xmmword ptr [rsi] + movups xmm5, xmmword ptr [rsi+0x10] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [rsi+0x20] + movups xmm7, xmmword ptr [rsi+0x30] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 0x93 + movaps xmm14, xmmword ptr [ROT8+rip] + movaps xmm15, xmmword ptr [ROT16+rip] + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x39 + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x93 + dec al + jz 9f + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0x0F + pshufd xmm4, xmm8, 0x39 + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0xCC + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0xC0 + pshufd xmm8, xmm8, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp 9b +9: + movdqu xmm4, xmmword ptr [rdi] + movdqu xmm5, xmmword ptr [rdi+0x10] + pxor xmm0, xmm2 + pxor xmm1, xmm3 + pxor xmm2, xmm4 + pxor xmm3, xmm5 + movups xmmword ptr [r9], xmm0 + movups xmmword ptr [r9+0x10], xmm1 + movups xmmword ptr [r9+0x20], xmm2 + movups xmmword ptr [r9+0x30], xmm3 + ret + + +#ifdef __APPLE__ +.static_data +#else +.section .rodata +#endif +.p2align 6 +BLAKE3_IV: + .long 0x6A09E667, 0xBB67AE85 + .long 0x3C6EF372, 0xA54FF53A +ROT16: + .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 +ROT8: + .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 +ADD0: + .long 0, 1, 2, 3 +ADD1: + .long 4, 4, 4, 4 +BLAKE3_IV_0: + .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 +BLAKE3_IV_1: + .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 +BLAKE3_IV_2: + .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 +BLAKE3_IV_3: + .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A +BLAKE3_BLOCK_LEN: + .long 64, 64, 64, 64 +CMP_MSB_MASK: + .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 diff --git a/src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_gnu.S b/src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_gnu.S new file mode 100644 index 000000000..60d0a4042 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_gnu.S @@ -0,0 +1,2069 @@ +.intel_syntax noprefix +.global blake3_hash_many_sse41 +.global _blake3_hash_many_sse41 +.global blake3_compress_in_place_sse41 +.global _blake3_compress_in_place_sse41 +.global blake3_compress_xof_sse41 +.global _blake3_compress_xof_sse41 +.section .text + .p2align 6 +_blake3_hash_many_sse41: +blake3_hash_many_sse41: + push r15 + push r14 + push r13 + push r12 + push rsi + push rdi + push rbx + push rbp + mov rbp, rsp + sub rsp, 528 + and rsp, 0xFFFFFFFFFFFFFFC0 + movdqa xmmword ptr [rsp+0x170], xmm6 + movdqa xmmword ptr [rsp+0x180], xmm7 + movdqa xmmword ptr [rsp+0x190], xmm8 + movdqa xmmword ptr [rsp+0x1A0], xmm9 + movdqa xmmword ptr [rsp+0x1B0], xmm10 + movdqa xmmword ptr [rsp+0x1C0], xmm11 + movdqa xmmword ptr [rsp+0x1D0], xmm12 + movdqa xmmword ptr [rsp+0x1E0], xmm13 + movdqa xmmword ptr [rsp+0x1F0], xmm14 + movdqa xmmword ptr [rsp+0x200], xmm15 + mov rdi, rcx + mov rsi, rdx + mov rdx, r8 + mov rcx, r9 + mov r8, qword ptr [rbp+0x68] + movzx r9, byte ptr [rbp+0x70] + neg r9d + movd xmm0, r9d + pshufd xmm0, xmm0, 0x00 + movdqa xmmword ptr [rsp+0x130], xmm0 + movdqa xmm1, xmm0 + pand xmm1, xmmword ptr [ADD0+rip] + pand xmm0, xmmword ptr [ADD1+rip] + movdqa xmmword ptr [rsp+0x150], xmm0 + movd xmm0, r8d + pshufd xmm0, xmm0, 0x00 + paddd xmm0, xmm1 + movdqa xmmword ptr [rsp+0x110], xmm0 + pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] + pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] + pcmpgtd xmm1, xmm0 + shr r8, 32 + movd xmm2, r8d + pshufd xmm2, xmm2, 0x00 + psubd xmm2, xmm1 + movdqa xmmword ptr [rsp+0x120], xmm2 + mov rbx, qword ptr [rbp+0x90] + mov r15, rdx + shl r15, 6 + movzx r13d, byte ptr [rbp+0x78] + movzx r12d, byte ptr [rbp+0x88] + cmp rsi, 4 + jc 3f +2: + movdqu xmm3, xmmword ptr [rcx] + pshufd xmm0, xmm3, 0x00 + pshufd xmm1, xmm3, 0x55 + pshufd xmm2, xmm3, 0xAA + pshufd xmm3, xmm3, 0xFF + movdqu xmm7, xmmword ptr [rcx+0x10] + pshufd xmm4, xmm7, 0x00 + pshufd xmm5, xmm7, 0x55 + pshufd xmm6, xmm7, 0xAA + pshufd xmm7, xmm7, 0xFF + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + mov r10, qword ptr [rdi+0x10] + mov r11, qword ptr [rdi+0x18] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +9: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movdqu xmm8, xmmword ptr [r8+rdx-0x40] + movdqu xmm9, xmmword ptr [r9+rdx-0x40] + movdqu xmm10, xmmword ptr [r10+rdx-0x40] + movdqu xmm11, xmmword ptr [r11+rdx-0x40] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp], xmm8 + movdqa xmmword ptr [rsp+0x10], xmm9 + movdqa xmmword ptr [rsp+0x20], xmm12 + movdqa xmmword ptr [rsp+0x30], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-0x30] + movdqu xmm9, xmmword ptr [r9+rdx-0x30] + movdqu xmm10, xmmword ptr [r10+rdx-0x30] + movdqu xmm11, xmmword ptr [r11+rdx-0x30] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+0x40], xmm8 + movdqa xmmword ptr [rsp+0x50], xmm9 + movdqa xmmword ptr [rsp+0x60], xmm12 + movdqa xmmword ptr [rsp+0x70], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-0x20] + movdqu xmm9, xmmword ptr [r9+rdx-0x20] + movdqu xmm10, xmmword ptr [r10+rdx-0x20] + movdqu xmm11, xmmword ptr [r11+rdx-0x20] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+0x80], xmm8 + movdqa xmmword ptr [rsp+0x90], xmm9 + movdqa xmmword ptr [rsp+0xA0], xmm12 + movdqa xmmword ptr [rsp+0xB0], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-0x10] + movdqu xmm9, xmmword ptr [r9+rdx-0x10] + movdqu xmm10, xmmword ptr [r10+rdx-0x10] + movdqu xmm11, xmmword ptr [r11+rdx-0x10] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+0xC0], xmm8 + movdqa xmmword ptr [rsp+0xD0], xmm9 + movdqa xmmword ptr [rsp+0xE0], xmm12 + movdqa xmmword ptr [rsp+0xF0], xmm13 + movdqa xmm9, xmmword ptr [BLAKE3_IV_1+rip] + movdqa xmm10, xmmword ptr [BLAKE3_IV_2+rip] + movdqa xmm11, xmmword ptr [BLAKE3_IV_3+rip] + movdqa xmm12, xmmword ptr [rsp+0x110] + movdqa xmm13, xmmword ptr [rsp+0x120] + movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN+rip] + movd xmm15, eax + pshufd xmm15, xmm15, 0x00 + prefetcht0 [r8+rdx+0x80] + prefetcht0 [r9+rdx+0x80] + prefetcht0 [r10+rdx+0x80] + prefetcht0 [r11+rdx+0x80] + paddd xmm0, xmmword ptr [rsp] + paddd xmm1, xmmword ptr [rsp+0x20] + paddd xmm2, xmmword ptr [rsp+0x40] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [BLAKE3_IV_0+rip] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x10] + paddd xmm1, xmmword ptr [rsp+0x30] + paddd xmm2, xmmword ptr [rsp+0x50] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x80] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp+0xC0] + paddd xmm3, xmmword ptr [rsp+0xE0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x90] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0xD0] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x20] + paddd xmm1, xmmword ptr [rsp+0x30] + paddd xmm2, xmmword ptr [rsp+0x70] + paddd xmm3, xmmword ptr [rsp+0x40] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x60] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp] + paddd xmm3, xmmword ptr [rsp+0xD0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x10] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0x90] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xB0] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp+0xE0] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x30] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp+0xD0] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x40] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0x20] + paddd xmm3, xmmword ptr [rsp+0xE0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x60] + paddd xmm1, xmmword ptr [rsp+0x90] + paddd xmm2, xmmword ptr [rsp+0xB0] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x50] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+0xF0] + paddd xmm3, xmmword ptr [rsp+0x10] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xA0] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0xE0] + paddd xmm3, xmmword ptr [rsp+0xD0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x70] + paddd xmm1, xmmword ptr [rsp+0x90] + paddd xmm2, xmmword ptr [rsp+0x30] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x40] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0x50] + paddd xmm3, xmmword ptr [rsp+0x10] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp] + paddd xmm1, xmmword ptr [rsp+0x20] + paddd xmm2, xmmword ptr [rsp+0x80] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xC0] + paddd xmm1, xmmword ptr [rsp+0x90] + paddd xmm2, xmmword ptr [rsp+0xF0] + paddd xmm3, xmmword ptr [rsp+0xE0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xD0] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0xA0] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0x70] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x20] + paddd xmm1, xmmword ptr [rsp+0x30] + paddd xmm2, xmmword ptr [rsp+0x10] + paddd xmm3, xmmword ptr [rsp+0x40] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x90] + paddd xmm1, xmmword ptr [rsp+0xB0] + paddd xmm2, xmmword ptr [rsp+0x80] + paddd xmm3, xmmword ptr [rsp+0xF0] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xE0] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp+0xC0] + paddd xmm3, xmmword ptr [rsp+0x10] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xD0] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+0x20] + paddd xmm3, xmmword ptr [rsp+0x40] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0x30] + paddd xmm1, xmmword ptr [rsp+0xA0] + paddd xmm2, xmmword ptr [rsp+0x60] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xB0] + paddd xmm1, xmmword ptr [rsp+0x50] + paddd xmm2, xmmword ptr [rsp+0x10] + paddd xmm3, xmmword ptr [rsp+0x80] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xF0] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+0x90] + paddd xmm3, xmmword ptr [rsp+0x60] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0xE0] + paddd xmm1, xmmword ptr [rsp+0x20] + paddd xmm2, xmmword ptr [rsp+0x30] + paddd xmm3, xmmword ptr [rsp+0x70] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+0x100], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0xA0] + paddd xmm1, xmmword ptr [rsp+0xC0] + paddd xmm2, xmmword ptr [rsp+0x40] + paddd xmm3, xmmword ptr [rsp+0xD0] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8+rip] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+0x100] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + pxor xmm0, xmm8 + pxor xmm1, xmm9 + pxor xmm2, xmm10 + pxor xmm3, xmm11 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + pxor xmm4, xmm12 + pxor xmm5, xmm13 + pxor xmm6, xmm14 + pxor xmm7, xmm15 + mov eax, r13d + jne 9b + movdqa xmm9, xmm0 + punpckldq xmm0, xmm1 + punpckhdq xmm9, xmm1 + movdqa xmm11, xmm2 + punpckldq xmm2, xmm3 + punpckhdq xmm11, xmm3 + movdqa xmm1, xmm0 + punpcklqdq xmm0, xmm2 + punpckhqdq xmm1, xmm2 + movdqa xmm3, xmm9 + punpcklqdq xmm9, xmm11 + punpckhqdq xmm3, xmm11 + movdqu xmmword ptr [rbx], xmm0 + movdqu xmmword ptr [rbx+0x20], xmm1 + movdqu xmmword ptr [rbx+0x40], xmm9 + movdqu xmmword ptr [rbx+0x60], xmm3 + movdqa xmm9, xmm4 + punpckldq xmm4, xmm5 + punpckhdq xmm9, xmm5 + movdqa xmm11, xmm6 + punpckldq xmm6, xmm7 + punpckhdq xmm11, xmm7 + movdqa xmm5, xmm4 + punpcklqdq xmm4, xmm6 + punpckhqdq xmm5, xmm6 + movdqa xmm7, xmm9 + punpcklqdq xmm9, xmm11 + punpckhqdq xmm7, xmm11 + movdqu xmmword ptr [rbx+0x10], xmm4 + movdqu xmmword ptr [rbx+0x30], xmm5 + movdqu xmmword ptr [rbx+0x50], xmm9 + movdqu xmmword ptr [rbx+0x70], xmm7 + movdqa xmm1, xmmword ptr [rsp+0x110] + movdqa xmm0, xmm1 + paddd xmm1, xmmword ptr [rsp+0x150] + movdqa xmmword ptr [rsp+0x110], xmm1 + pxor xmm0, xmmword ptr [CMP_MSB_MASK+rip] + pxor xmm1, xmmword ptr [CMP_MSB_MASK+rip] + pcmpgtd xmm0, xmm1 + movdqa xmm1, xmmword ptr [rsp+0x120] + psubd xmm1, xmm0 + movdqa xmmword ptr [rsp+0x120], xmm1 + add rbx, 128 + add rdi, 32 + sub rsi, 4 + cmp rsi, 4 + jnc 2b + test rsi, rsi + jne 3f +4: + movdqa xmm6, xmmword ptr [rsp+0x170] + movdqa xmm7, xmmword ptr [rsp+0x180] + movdqa xmm8, xmmword ptr [rsp+0x190] + movdqa xmm9, xmmword ptr [rsp+0x1A0] + movdqa xmm10, xmmword ptr [rsp+0x1B0] + movdqa xmm11, xmmword ptr [rsp+0x1C0] + movdqa xmm12, xmmword ptr [rsp+0x1D0] + movdqa xmm13, xmmword ptr [rsp+0x1E0] + movdqa xmm14, xmmword ptr [rsp+0x1F0] + movdqa xmm15, xmmword ptr [rsp+0x200] + mov rsp, rbp + pop rbp + pop rbx + pop rdi + pop rsi + pop r12 + pop r13 + pop r14 + pop r15 + ret +.p2align 5 +3: + test esi, 0x2 + je 3f + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+0x10] + movaps xmm8, xmm0 + movaps xmm9, xmm1 + movd xmm13, dword ptr [rsp+0x110] + pinsrd xmm13, dword ptr [rsp+0x120], 1 + pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + movaps xmmword ptr [rsp], xmm13 + movd xmm14, dword ptr [rsp+0x114] + pinsrd xmm14, dword ptr [rsp+0x124], 1 + pinsrd xmm14, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + movaps xmmword ptr [rsp+0x10], xmm14 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+0x8] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + movaps xmm10, xmm2 + movups xmm4, xmmword ptr [r8+rdx-0x40] + movups xmm5, xmmword ptr [r8+rdx-0x30] + movaps xmm3, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm3, xmm5, 221 + movaps xmm5, xmm3 + movups xmm6, xmmword ptr [r8+rdx-0x20] + movups xmm7, xmmword ptr [r8+rdx-0x10] + movaps xmm3, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm3, xmm7, 221 + pshufd xmm7, xmm3, 0x93 + movups xmm12, xmmword ptr [r9+rdx-0x40] + movups xmm13, xmmword ptr [r9+rdx-0x30] + movaps xmm11, xmm12 + shufps xmm12, xmm13, 136 + shufps xmm11, xmm13, 221 + movaps xmm13, xmm11 + movups xmm14, xmmword ptr [r9+rdx-0x20] + movups xmm15, xmmword ptr [r9+rdx-0x10] + movaps xmm11, xmm14 + shufps xmm14, xmm15, 136 + pshufd xmm14, xmm14, 0x93 + shufps xmm11, xmm15, 221 + pshufd xmm15, xmm11, 0x93 + movaps xmm3, xmmword ptr [rsp] + movaps xmm11, xmmword ptr [rsp+0x10] + pinsrd xmm3, eax, 3 + pinsrd xmm11, eax, 3 + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm8, xmm12 + movaps xmmword ptr [rsp+0x20], xmm4 + movaps xmmword ptr [rsp+0x30], xmm12 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + movaps xmm12, xmmword ptr [ROT16+rip] + pshufb xmm3, xmm12 + pshufb xmm11, xmm12 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 20 + psrld xmm4, 12 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 20 + psrld xmm4, 12 + por xmm9, xmm4 + paddd xmm0, xmm5 + paddd xmm8, xmm13 + movaps xmmword ptr [rsp+0x40], xmm5 + movaps xmmword ptr [rsp+0x50], xmm13 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + movaps xmm13, xmmword ptr [ROT8+rip] + pshufb xmm3, xmm13 + pshufb xmm11, xmm13 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 25 + psrld xmm4, 7 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 25 + psrld xmm4, 7 + por xmm9, xmm4 + pshufd xmm0, xmm0, 0x93 + pshufd xmm8, xmm8, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm11, xmm11, 0x4E + pshufd xmm2, xmm2, 0x39 + pshufd xmm10, xmm10, 0x39 + paddd xmm0, xmm6 + paddd xmm8, xmm14 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + pshufb xmm3, xmm12 + pshufb xmm11, xmm12 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 20 + psrld xmm4, 12 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 20 + psrld xmm4, 12 + por xmm9, xmm4 + paddd xmm0, xmm7 + paddd xmm8, xmm15 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + pshufb xmm3, xmm13 + pshufb xmm11, xmm13 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 25 + psrld xmm4, 7 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 25 + psrld xmm4, 7 + por xmm9, xmm4 + pshufd xmm0, xmm0, 0x39 + pshufd xmm8, xmm8, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm11, xmm11, 0x4E + pshufd xmm2, xmm2, 0x93 + pshufd xmm10, xmm10, 0x93 + dec al + je 9f + movdqa xmm12, xmmword ptr [rsp+0x20] + movdqa xmm5, xmmword ptr [rsp+0x40] + pshufd xmm13, xmm12, 0x0F + shufps xmm12, xmm5, 214 + pshufd xmm4, xmm12, 0x39 + movdqa xmm12, xmm6 + shufps xmm12, xmm7, 250 + pblendw xmm13, xmm12, 0xCC + movdqa xmm12, xmm7 + punpcklqdq xmm12, xmm5 + pblendw xmm12, xmm6, 0xC0 + pshufd xmm12, xmm12, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmmword ptr [rsp+0x20], xmm13 + movdqa xmmword ptr [rsp+0x40], xmm12 + movdqa xmm5, xmmword ptr [rsp+0x30] + movdqa xmm13, xmmword ptr [rsp+0x50] + pshufd xmm6, xmm5, 0x0F + shufps xmm5, xmm13, 214 + pshufd xmm12, xmm5, 0x39 + movdqa xmm5, xmm14 + shufps xmm5, xmm15, 250 + pblendw xmm6, xmm5, 0xCC + movdqa xmm5, xmm15 + punpcklqdq xmm5, xmm13 + pblendw xmm5, xmm14, 0xC0 + pshufd xmm5, xmm5, 0x78 + punpckhdq xmm13, xmm15 + punpckldq xmm14, xmm13 + pshufd xmm15, xmm14, 0x1E + movdqa xmm13, xmm6 + movdqa xmm14, xmm5 + movdqa xmm5, xmmword ptr [rsp+0x20] + movdqa xmm6, xmmword ptr [rsp+0x40] + jmp 9b +9: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + pxor xmm8, xmm10 + pxor xmm9, xmm11 + mov eax, r13d + cmp rdx, r15 + jne 2b + movups xmmword ptr [rbx], xmm0 + movups xmmword ptr [rbx+0x10], xmm1 + movups xmmword ptr [rbx+0x20], xmm8 + movups xmmword ptr [rbx+0x30], xmm9 + movdqa xmm0, xmmword ptr [rsp+0x130] + movdqa xmm1, xmmword ptr [rsp+0x110] + movdqa xmm2, xmmword ptr [rsp+0x120] + movdqu xmm3, xmmword ptr [rsp+0x118] + movdqu xmm4, xmmword ptr [rsp+0x128] + blendvps xmm1, xmm3, xmm0 + blendvps xmm2, xmm4, xmm0 + movdqa xmmword ptr [rsp+0x110], xmm1 + movdqa xmmword ptr [rsp+0x120], xmm2 + add rdi, 16 + add rbx, 64 + sub rsi, 2 +3: + test esi, 0x1 + je 4b + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+0x10] + movd xmm13, dword ptr [rsp+0x110] + pinsrd xmm13, dword ptr [rsp+0x120], 1 + pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN+rip], 2 + movaps xmm14, xmmword ptr [ROT8+rip] + movaps xmm15, xmmword ptr [ROT16+rip] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+0x80] + or eax, r13d + xor edx, edx +2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + movaps xmm3, xmm13 + pinsrd xmm3, eax, 3 + movups xmm4, xmmword ptr [r8+rdx-0x40] + movups xmm5, xmmword ptr [r8+rdx-0x30] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [r8+rdx-0x20] + movups xmm7, xmmword ptr [r8+rdx-0x10] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 0x93 + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x39 + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x93 + dec al + jz 9f + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0x0F + pshufd xmm4, xmm8, 0x39 + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0xCC + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0xC0 + pshufd xmm8, xmm8, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp 9b +9: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne 2b + movups xmmword ptr [rbx], xmm0 + movups xmmword ptr [rbx+0x10], xmm1 + jmp 4b + +.p2align 6 +blake3_compress_in_place_sse41: +_blake3_compress_in_place_sse41: + sub rsp, 120 + movdqa xmmword ptr [rsp], xmm6 + movdqa xmmword ptr [rsp+0x10], xmm7 + movdqa xmmword ptr [rsp+0x20], xmm8 + movdqa xmmword ptr [rsp+0x30], xmm9 + movdqa xmmword ptr [rsp+0x40], xmm11 + movdqa xmmword ptr [rsp+0x50], xmm14 + movdqa xmmword ptr [rsp+0x60], xmm15 + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+0x10] + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + movzx eax, byte ptr [rsp+0xA0] + movzx r8d, r8b + shl rax, 32 + add r8, rax + movq xmm3, r9 + movq xmm4, r8 + punpcklqdq xmm3, xmm4 + movups xmm4, xmmword ptr [rdx] + movups xmm5, xmmword ptr [rdx+0x10] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [rdx+0x20] + movups xmm7, xmmword ptr [rdx+0x30] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 0x93 + movaps xmm14, xmmword ptr [ROT8+rip] + movaps xmm15, xmmword ptr [ROT16+rip] + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x39 + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x93 + dec al + jz 9f + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0x0F + pshufd xmm4, xmm8, 0x39 + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0xCC + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0xC0 + pshufd xmm8, xmm8, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp 9b +9: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + movups xmmword ptr [rcx], xmm0 + movups xmmword ptr [rcx+0x10], xmm1 + movdqa xmm6, xmmword ptr [rsp] + movdqa xmm7, xmmword ptr [rsp+0x10] + movdqa xmm8, xmmword ptr [rsp+0x20] + movdqa xmm9, xmmword ptr [rsp+0x30] + movdqa xmm11, xmmword ptr [rsp+0x40] + movdqa xmm14, xmmword ptr [rsp+0x50] + movdqa xmm15, xmmword ptr [rsp+0x60] + add rsp, 120 + ret + + +.p2align 6 +_blake3_compress_xof_sse41: +blake3_compress_xof_sse41: + sub rsp, 120 + movdqa xmmword ptr [rsp], xmm6 + movdqa xmmword ptr [rsp+0x10], xmm7 + movdqa xmmword ptr [rsp+0x20], xmm8 + movdqa xmmword ptr [rsp+0x30], xmm9 + movdqa xmmword ptr [rsp+0x40], xmm11 + movdqa xmmword ptr [rsp+0x50], xmm14 + movdqa xmmword ptr [rsp+0x60], xmm15 + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+0x10] + movaps xmm2, xmmword ptr [BLAKE3_IV+rip] + movzx eax, byte ptr [rsp+0xA0] + movzx r8d, r8b + mov r10, qword ptr [rsp+0xA8] + shl rax, 32 + add r8, rax + movq xmm3, r9 + movq xmm4, r8 + punpcklqdq xmm3, xmm4 + movups xmm4, xmmword ptr [rdx] + movups xmm5, xmmword ptr [rdx+0x10] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [rdx+0x20] + movups xmm7, xmmword ptr [rdx+0x30] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 0x93 + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 0x93 + movaps xmm14, xmmword ptr [ROT8+rip] + movaps xmm15, xmmword ptr [ROT16+rip] + mov al, 7 +9: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x93 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x39 + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 0x39 + pshufd xmm3, xmm3, 0x4E + pshufd xmm2, xmm2, 0x93 + dec al + jz 9f + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0x0F + pshufd xmm4, xmm8, 0x39 + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0xCC + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0xC0 + pshufd xmm8, xmm8, 0x78 + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 0x1E + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp 9b +9: + movdqu xmm4, xmmword ptr [rcx] + movdqu xmm5, xmmword ptr [rcx+0x10] + pxor xmm0, xmm2 + pxor xmm1, xmm3 + pxor xmm2, xmm4 + pxor xmm3, xmm5 + movups xmmword ptr [r10], xmm0 + movups xmmword ptr [r10+0x10], xmm1 + movups xmmword ptr [r10+0x20], xmm2 + movups xmmword ptr [r10+0x30], xmm3 + movdqa xmm6, xmmword ptr [rsp] + movdqa xmm7, xmmword ptr [rsp+0x10] + movdqa xmm8, xmmword ptr [rsp+0x20] + movdqa xmm9, xmmword ptr [rsp+0x30] + movdqa xmm11, xmmword ptr [rsp+0x40] + movdqa xmm14, xmmword ptr [rsp+0x50] + movdqa xmm15, xmmword ptr [rsp+0x60] + add rsp, 120 + ret + + +.section .rodata +.p2align 6 +BLAKE3_IV: + .long 0x6A09E667, 0xBB67AE85 + .long 0x3C6EF372, 0xA54FF53A +ROT16: + .byte 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 +ROT8: + .byte 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 +ADD0: + .long 0, 1, 2, 3 +ADD1: + .long 4, 4, 4, 4 +BLAKE3_IV_0: + .long 0x6A09E667, 0x6A09E667, 0x6A09E667, 0x6A09E667 +BLAKE3_IV_1: + .long 0xBB67AE85, 0xBB67AE85, 0xBB67AE85, 0xBB67AE85 +BLAKE3_IV_2: + .long 0x3C6EF372, 0x3C6EF372, 0x3C6EF372, 0x3C6EF372 +BLAKE3_IV_3: + .long 0xA54FF53A, 0xA54FF53A, 0xA54FF53A, 0xA54FF53A +BLAKE3_BLOCK_LEN: + .long 64, 64, 64, 64 +CMP_MSB_MASK: + .long 0x80000000, 0x80000000, 0x80000000, 0x80000000 diff --git a/src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_msvc.asm b/src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_msvc.asm new file mode 100644 index 000000000..87001e4d3 --- /dev/null +++ b/src/Native/libmultihash/blake3/blake3_sse41_x86-64_windows_msvc.asm @@ -0,0 +1,2089 @@ +public _blake3_hash_many_sse41 +public blake3_hash_many_sse41 +public blake3_compress_in_place_sse41 +public _blake3_compress_in_place_sse41 +public blake3_compress_xof_sse41 +public _blake3_compress_xof_sse41 + +_TEXT SEGMENT ALIGN(16) 'CODE' + +ALIGN 16 +blake3_hash_many_sse41 PROC +_blake3_hash_many_sse41 PROC + push r15 + push r14 + push r13 + push r12 + push rsi + push rdi + push rbx + push rbp + mov rbp, rsp + sub rsp, 528 + and rsp, 0FFFFFFFFFFFFFFC0H + movdqa xmmword ptr [rsp+170H], xmm6 + movdqa xmmword ptr [rsp+180H], xmm7 + movdqa xmmword ptr [rsp+190H], xmm8 + movdqa xmmword ptr [rsp+1A0H], xmm9 + movdqa xmmword ptr [rsp+1B0H], xmm10 + movdqa xmmword ptr [rsp+1C0H], xmm11 + movdqa xmmword ptr [rsp+1D0H], xmm12 + movdqa xmmword ptr [rsp+1E0H], xmm13 + movdqa xmmword ptr [rsp+1F0H], xmm14 + movdqa xmmword ptr [rsp+200H], xmm15 + mov rdi, rcx + mov rsi, rdx + mov rdx, r8 + mov rcx, r9 + mov r8, qword ptr [rbp+68H] + movzx r9, byte ptr [rbp+70H] + neg r9d + movd xmm0, r9d + pshufd xmm0, xmm0, 00H + movdqa xmmword ptr [rsp+130H], xmm0 + movdqa xmm1, xmm0 + pand xmm1, xmmword ptr [ADD0] + pand xmm0, xmmword ptr [ADD1] + movdqa xmmword ptr [rsp+150H], xmm0 + movd xmm0, r8d + pshufd xmm0, xmm0, 00H + paddd xmm0, xmm1 + movdqa xmmword ptr [rsp+110H], xmm0 + pxor xmm0, xmmword ptr [CMP_MSB_MASK] + pxor xmm1, xmmword ptr [CMP_MSB_MASK] + pcmpgtd xmm1, xmm0 + shr r8, 32 + movd xmm2, r8d + pshufd xmm2, xmm2, 00H + psubd xmm2, xmm1 + movdqa xmmword ptr [rsp+120H], xmm2 + mov rbx, qword ptr [rbp+90H] + mov r15, rdx + shl r15, 6 + movzx r13d, byte ptr [rbp+78H] + movzx r12d, byte ptr [rbp+88H] + cmp rsi, 4 + jc final3blocks +outerloop4: + movdqu xmm3, xmmword ptr [rcx] + pshufd xmm0, xmm3, 00H + pshufd xmm1, xmm3, 55H + pshufd xmm2, xmm3, 0AAH + pshufd xmm3, xmm3, 0FFH + movdqu xmm7, xmmword ptr [rcx+10H] + pshufd xmm4, xmm7, 00H + pshufd xmm5, xmm7, 55H + pshufd xmm6, xmm7, 0AAH + pshufd xmm7, xmm7, 0FFH + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + mov r10, qword ptr [rdi+10H] + mov r11, qword ptr [rdi+18H] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +innerloop4: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movdqu xmm8, xmmword ptr [r8+rdx-40H] + movdqu xmm9, xmmword ptr [r9+rdx-40H] + movdqu xmm10, xmmword ptr [r10+rdx-40H] + movdqu xmm11, xmmword ptr [r11+rdx-40H] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp], xmm8 + movdqa xmmword ptr [rsp+10H], xmm9 + movdqa xmmword ptr [rsp+20H], xmm12 + movdqa xmmword ptr [rsp+30H], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-30H] + movdqu xmm9, xmmword ptr [r9+rdx-30H] + movdqu xmm10, xmmword ptr [r10+rdx-30H] + movdqu xmm11, xmmword ptr [r11+rdx-30H] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+40H], xmm8 + movdqa xmmword ptr [rsp+50H], xmm9 + movdqa xmmword ptr [rsp+60H], xmm12 + movdqa xmmword ptr [rsp+70H], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-20H] + movdqu xmm9, xmmword ptr [r9+rdx-20H] + movdqu xmm10, xmmword ptr [r10+rdx-20H] + movdqu xmm11, xmmword ptr [r11+rdx-20H] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+80H], xmm8 + movdqa xmmword ptr [rsp+90H], xmm9 + movdqa xmmword ptr [rsp+0A0H], xmm12 + movdqa xmmword ptr [rsp+0B0H], xmm13 + movdqu xmm8, xmmword ptr [r8+rdx-10H] + movdqu xmm9, xmmword ptr [r9+rdx-10H] + movdqu xmm10, xmmword ptr [r10+rdx-10H] + movdqu xmm11, xmmword ptr [r11+rdx-10H] + movdqa xmm12, xmm8 + punpckldq xmm8, xmm9 + punpckhdq xmm12, xmm9 + movdqa xmm14, xmm10 + punpckldq xmm10, xmm11 + punpckhdq xmm14, xmm11 + movdqa xmm9, xmm8 + punpcklqdq xmm8, xmm10 + punpckhqdq xmm9, xmm10 + movdqa xmm13, xmm12 + punpcklqdq xmm12, xmm14 + punpckhqdq xmm13, xmm14 + movdqa xmmword ptr [rsp+0C0H], xmm8 + movdqa xmmword ptr [rsp+0D0H], xmm9 + movdqa xmmword ptr [rsp+0E0H], xmm12 + movdqa xmmword ptr [rsp+0F0H], xmm13 + movdqa xmm9, xmmword ptr [BLAKE3_IV_1] + movdqa xmm10, xmmword ptr [BLAKE3_IV_2] + movdqa xmm11, xmmword ptr [BLAKE3_IV_3] + movdqa xmm12, xmmword ptr [rsp+110H] + movdqa xmm13, xmmword ptr [rsp+120H] + movdqa xmm14, xmmword ptr [BLAKE3_BLOCK_LEN] + movd xmm15, eax + pshufd xmm15, xmm15, 00H + prefetcht0 byte ptr [r8+rdx+80H] + prefetcht0 byte ptr [r9+rdx+80H] + prefetcht0 byte ptr [r10+rdx+80H] + prefetcht0 byte ptr [r11+rdx+80H] + paddd xmm0, xmmword ptr [rsp] + paddd xmm1, xmmword ptr [rsp+20H] + paddd xmm2, xmmword ptr [rsp+40H] + paddd xmm3, xmmword ptr [rsp+60H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [BLAKE3_IV_0] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+10H] + paddd xmm1, xmmword ptr [rsp+30H] + paddd xmm2, xmmword ptr [rsp+50H] + paddd xmm3, xmmword ptr [rsp+70H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+80H] + paddd xmm1, xmmword ptr [rsp+0A0H] + paddd xmm2, xmmword ptr [rsp+0C0H] + paddd xmm3, xmmword ptr [rsp+0E0H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+90H] + paddd xmm1, xmmword ptr [rsp+0B0H] + paddd xmm2, xmmword ptr [rsp+0D0H] + paddd xmm3, xmmword ptr [rsp+0F0H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+20H] + paddd xmm1, xmmword ptr [rsp+30H] + paddd xmm2, xmmword ptr [rsp+70H] + paddd xmm3, xmmword ptr [rsp+40H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+60H] + paddd xmm1, xmmword ptr [rsp+0A0H] + paddd xmm2, xmmword ptr [rsp] + paddd xmm3, xmmword ptr [rsp+0D0H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+10H] + paddd xmm1, xmmword ptr [rsp+0C0H] + paddd xmm2, xmmword ptr [rsp+90H] + paddd xmm3, xmmword ptr [rsp+0F0H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0B0H] + paddd xmm1, xmmword ptr [rsp+50H] + paddd xmm2, xmmword ptr [rsp+0E0H] + paddd xmm3, xmmword ptr [rsp+80H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+30H] + paddd xmm1, xmmword ptr [rsp+0A0H] + paddd xmm2, xmmword ptr [rsp+0D0H] + paddd xmm3, xmmword ptr [rsp+70H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+40H] + paddd xmm1, xmmword ptr [rsp+0C0H] + paddd xmm2, xmmword ptr [rsp+20H] + paddd xmm3, xmmword ptr [rsp+0E0H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+60H] + paddd xmm1, xmmword ptr [rsp+90H] + paddd xmm2, xmmword ptr [rsp+0B0H] + paddd xmm3, xmmword ptr [rsp+80H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+50H] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+0F0H] + paddd xmm3, xmmword ptr [rsp+10H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0A0H] + paddd xmm1, xmmword ptr [rsp+0C0H] + paddd xmm2, xmmword ptr [rsp+0E0H] + paddd xmm3, xmmword ptr [rsp+0D0H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+70H] + paddd xmm1, xmmword ptr [rsp+90H] + paddd xmm2, xmmword ptr [rsp+30H] + paddd xmm3, xmmword ptr [rsp+0F0H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+40H] + paddd xmm1, xmmword ptr [rsp+0B0H] + paddd xmm2, xmmword ptr [rsp+50H] + paddd xmm3, xmmword ptr [rsp+10H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp] + paddd xmm1, xmmword ptr [rsp+20H] + paddd xmm2, xmmword ptr [rsp+80H] + paddd xmm3, xmmword ptr [rsp+60H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0C0H] + paddd xmm1, xmmword ptr [rsp+90H] + paddd xmm2, xmmword ptr [rsp+0F0H] + paddd xmm3, xmmword ptr [rsp+0E0H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0D0H] + paddd xmm1, xmmword ptr [rsp+0B0H] + paddd xmm2, xmmword ptr [rsp+0A0H] + paddd xmm3, xmmword ptr [rsp+80H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+70H] + paddd xmm1, xmmword ptr [rsp+50H] + paddd xmm2, xmmword ptr [rsp] + paddd xmm3, xmmword ptr [rsp+60H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+20H] + paddd xmm1, xmmword ptr [rsp+30H] + paddd xmm2, xmmword ptr [rsp+10H] + paddd xmm3, xmmword ptr [rsp+40H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+90H] + paddd xmm1, xmmword ptr [rsp+0B0H] + paddd xmm2, xmmword ptr [rsp+80H] + paddd xmm3, xmmword ptr [rsp+0F0H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0E0H] + paddd xmm1, xmmword ptr [rsp+50H] + paddd xmm2, xmmword ptr [rsp+0C0H] + paddd xmm3, xmmword ptr [rsp+10H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0D0H] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+20H] + paddd xmm3, xmmword ptr [rsp+40H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+30H] + paddd xmm1, xmmword ptr [rsp+0A0H] + paddd xmm2, xmmword ptr [rsp+60H] + paddd xmm3, xmmword ptr [rsp+70H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0B0H] + paddd xmm1, xmmword ptr [rsp+50H] + paddd xmm2, xmmword ptr [rsp+10H] + paddd xmm3, xmmword ptr [rsp+80H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0F0H] + paddd xmm1, xmmword ptr [rsp] + paddd xmm2, xmmword ptr [rsp+90H] + paddd xmm3, xmmword ptr [rsp+60H] + paddd xmm0, xmm4 + paddd xmm1, xmm5 + paddd xmm2, xmm6 + paddd xmm3, xmm7 + pxor xmm12, xmm0 + pxor xmm13, xmm1 + pxor xmm14, xmm2 + pxor xmm15, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + pshufb xmm15, xmm8 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm12 + paddd xmm9, xmm13 + paddd xmm10, xmm14 + paddd xmm11, xmm15 + pxor xmm4, xmm8 + pxor xmm5, xmm9 + pxor xmm6, xmm10 + pxor xmm7, xmm11 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + paddd xmm0, xmmword ptr [rsp+0E0H] + paddd xmm1, xmmword ptr [rsp+20H] + paddd xmm2, xmmword ptr [rsp+30H] + paddd xmm3, xmmword ptr [rsp+70H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT16] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + movdqa xmmword ptr [rsp+100H], xmm8 + movdqa xmm8, xmm5 + psrld xmm8, 12 + pslld xmm5, 20 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 12 + pslld xmm6, 20 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 12 + pslld xmm7, 20 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 12 + pslld xmm4, 20 + por xmm4, xmm8 + paddd xmm0, xmmword ptr [rsp+0A0H] + paddd xmm1, xmmword ptr [rsp+0C0H] + paddd xmm2, xmmword ptr [rsp+40H] + paddd xmm3, xmmword ptr [rsp+0D0H] + paddd xmm0, xmm5 + paddd xmm1, xmm6 + paddd xmm2, xmm7 + paddd xmm3, xmm4 + pxor xmm15, xmm0 + pxor xmm12, xmm1 + pxor xmm13, xmm2 + pxor xmm14, xmm3 + movdqa xmm8, xmmword ptr [ROT8] + pshufb xmm15, xmm8 + pshufb xmm12, xmm8 + pshufb xmm13, xmm8 + pshufb xmm14, xmm8 + paddd xmm10, xmm15 + paddd xmm11, xmm12 + movdqa xmm8, xmmword ptr [rsp+100H] + paddd xmm8, xmm13 + paddd xmm9, xmm14 + pxor xmm5, xmm10 + pxor xmm6, xmm11 + pxor xmm7, xmm8 + pxor xmm4, xmm9 + pxor xmm0, xmm8 + pxor xmm1, xmm9 + pxor xmm2, xmm10 + pxor xmm3, xmm11 + movdqa xmm8, xmm5 + psrld xmm8, 7 + pslld xmm5, 25 + por xmm5, xmm8 + movdqa xmm8, xmm6 + psrld xmm8, 7 + pslld xmm6, 25 + por xmm6, xmm8 + movdqa xmm8, xmm7 + psrld xmm8, 7 + pslld xmm7, 25 + por xmm7, xmm8 + movdqa xmm8, xmm4 + psrld xmm8, 7 + pslld xmm4, 25 + por xmm4, xmm8 + pxor xmm4, xmm12 + pxor xmm5, xmm13 + pxor xmm6, xmm14 + pxor xmm7, xmm15 + mov eax, r13d + jne innerloop4 + movdqa xmm9, xmm0 + punpckldq xmm0, xmm1 + punpckhdq xmm9, xmm1 + movdqa xmm11, xmm2 + punpckldq xmm2, xmm3 + punpckhdq xmm11, xmm3 + movdqa xmm1, xmm0 + punpcklqdq xmm0, xmm2 + punpckhqdq xmm1, xmm2 + movdqa xmm3, xmm9 + punpcklqdq xmm9, xmm11 + punpckhqdq xmm3, xmm11 + movdqu xmmword ptr [rbx], xmm0 + movdqu xmmword ptr [rbx+20H], xmm1 + movdqu xmmword ptr [rbx+40H], xmm9 + movdqu xmmword ptr [rbx+60H], xmm3 + movdqa xmm9, xmm4 + punpckldq xmm4, xmm5 + punpckhdq xmm9, xmm5 + movdqa xmm11, xmm6 + punpckldq xmm6, xmm7 + punpckhdq xmm11, xmm7 + movdqa xmm5, xmm4 + punpcklqdq xmm4, xmm6 + punpckhqdq xmm5, xmm6 + movdqa xmm7, xmm9 + punpcklqdq xmm9, xmm11 + punpckhqdq xmm7, xmm11 + movdqu xmmword ptr [rbx+10H], xmm4 + movdqu xmmword ptr [rbx+30H], xmm5 + movdqu xmmword ptr [rbx+50H], xmm9 + movdqu xmmword ptr [rbx+70H], xmm7 + movdqa xmm1, xmmword ptr [rsp+110H] + movdqa xmm0, xmm1 + paddd xmm1, xmmword ptr [rsp+150H] + movdqa xmmword ptr [rsp+110H], xmm1 + pxor xmm0, xmmword ptr [CMP_MSB_MASK] + pxor xmm1, xmmword ptr [CMP_MSB_MASK] + pcmpgtd xmm0, xmm1 + movdqa xmm1, xmmword ptr [rsp+120H] + psubd xmm1, xmm0 + movdqa xmmword ptr [rsp+120H], xmm1 + add rbx, 128 + add rdi, 32 + sub rsi, 4 + cmp rsi, 4 + jnc outerloop4 + test rsi, rsi + jne final3blocks +unwind: + movdqa xmm6, xmmword ptr [rsp+170H] + movdqa xmm7, xmmword ptr [rsp+180H] + movdqa xmm8, xmmword ptr [rsp+190H] + movdqa xmm9, xmmword ptr [rsp+1A0H] + movdqa xmm10, xmmword ptr [rsp+1B0H] + movdqa xmm11, xmmword ptr [rsp+1C0H] + movdqa xmm12, xmmword ptr [rsp+1D0H] + movdqa xmm13, xmmword ptr [rsp+1E0H] + movdqa xmm14, xmmword ptr [rsp+1F0H] + movdqa xmm15, xmmword ptr [rsp+200H] + mov rsp, rbp + pop rbp + pop rbx + pop rdi + pop rsi + pop r12 + pop r13 + pop r14 + pop r15 + ret +ALIGN 16 +final3blocks: + test esi, 2H + je final1block + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+10H] + movaps xmm8, xmm0 + movaps xmm9, xmm1 + movd xmm13, dword ptr [rsp+110H] + pinsrd xmm13, dword ptr [rsp+120H], 1 + pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 + movaps xmmword ptr [rsp], xmm13 + movd xmm14, dword ptr [rsp+114H] + pinsrd xmm14, dword ptr [rsp+124H], 1 + pinsrd xmm14, dword ptr [BLAKE3_BLOCK_LEN], 2 + movaps xmmword ptr [rsp+10H], xmm14 + mov r8, qword ptr [rdi] + mov r9, qword ptr [rdi+8H] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +innerloop2: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movaps xmm2, xmmword ptr [BLAKE3_IV] + movaps xmm10, xmm2 + movups xmm4, xmmword ptr [r8+rdx-40H] + movups xmm5, xmmword ptr [r8+rdx-30H] + movaps xmm3, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm3, xmm5, 221 + movaps xmm5, xmm3 + movups xmm6, xmmword ptr [r8+rdx-20H] + movups xmm7, xmmword ptr [r8+rdx-10H] + movaps xmm3, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 93H + shufps xmm3, xmm7, 221 + pshufd xmm7, xmm3, 93H + movups xmm12, xmmword ptr [r9+rdx-40H] + movups xmm13, xmmword ptr [r9+rdx-30H] + movaps xmm11, xmm12 + shufps xmm12, xmm13, 136 + shufps xmm11, xmm13, 221 + movaps xmm13, xmm11 + movups xmm14, xmmword ptr [r9+rdx-20H] + movups xmm15, xmmword ptr [r9+rdx-10H] + movaps xmm11, xmm14 + shufps xmm14, xmm15, 136 + pshufd xmm14, xmm14, 93H + shufps xmm11, xmm15, 221 + pshufd xmm15, xmm11, 93H + movaps xmm3, xmmword ptr [rsp] + movaps xmm11, xmmword ptr [rsp+10H] + pinsrd xmm3, eax, 3 + pinsrd xmm11, eax, 3 + mov al, 7 +roundloop2: + paddd xmm0, xmm4 + paddd xmm8, xmm12 + movaps xmmword ptr [rsp+20H], xmm4 + movaps xmmword ptr [rsp+30H], xmm12 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + movaps xmm12, xmmword ptr [ROT16] + pshufb xmm3, xmm12 + pshufb xmm11, xmm12 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 20 + psrld xmm4, 12 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 20 + psrld xmm4, 12 + por xmm9, xmm4 + paddd xmm0, xmm5 + paddd xmm8, xmm13 + movaps xmmword ptr [rsp+40H], xmm5 + movaps xmmword ptr [rsp+50H], xmm13 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + movaps xmm13, xmmword ptr [ROT8] + pshufb xmm3, xmm13 + pshufb xmm11, xmm13 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 25 + psrld xmm4, 7 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 25 + psrld xmm4, 7 + por xmm9, xmm4 + pshufd xmm0, xmm0, 93H + pshufd xmm8, xmm8, 93H + pshufd xmm3, xmm3, 4EH + pshufd xmm11, xmm11, 4EH + pshufd xmm2, xmm2, 39H + pshufd xmm10, xmm10, 39H + paddd xmm0, xmm6 + paddd xmm8, xmm14 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + pshufb xmm3, xmm12 + pshufb xmm11, xmm12 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 20 + psrld xmm4, 12 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 20 + psrld xmm4, 12 + por xmm9, xmm4 + paddd xmm0, xmm7 + paddd xmm8, xmm15 + paddd xmm0, xmm1 + paddd xmm8, xmm9 + pxor xmm3, xmm0 + pxor xmm11, xmm8 + pshufb xmm3, xmm13 + pshufb xmm11, xmm13 + paddd xmm2, xmm3 + paddd xmm10, xmm11 + pxor xmm1, xmm2 + pxor xmm9, xmm10 + movdqa xmm4, xmm1 + pslld xmm1, 25 + psrld xmm4, 7 + por xmm1, xmm4 + movdqa xmm4, xmm9 + pslld xmm9, 25 + psrld xmm4, 7 + por xmm9, xmm4 + pshufd xmm0, xmm0, 39H + pshufd xmm8, xmm8, 39H + pshufd xmm3, xmm3, 4EH + pshufd xmm11, xmm11, 4EH + pshufd xmm2, xmm2, 93H + pshufd xmm10, xmm10, 93H + dec al + je endroundloop2 + movdqa xmm12, xmmword ptr [rsp+20H] + movdqa xmm5, xmmword ptr [rsp+40H] + pshufd xmm13, xmm12, 0FH + shufps xmm12, xmm5, 214 + pshufd xmm4, xmm12, 39H + movdqa xmm12, xmm6 + shufps xmm12, xmm7, 250 + pblendw xmm13, xmm12, 0CCH + movdqa xmm12, xmm7 + punpcklqdq xmm12, xmm5 + pblendw xmm12, xmm6, 0C0H + pshufd xmm12, xmm12, 78H + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 1EH + movdqa xmmword ptr [rsp+20H], xmm13 + movdqa xmmword ptr [rsp+40H], xmm12 + movdqa xmm5, xmmword ptr [rsp+30H] + movdqa xmm13, xmmword ptr [rsp+50H] + pshufd xmm6, xmm5, 0FH + shufps xmm5, xmm13, 214 + pshufd xmm12, xmm5, 39H + movdqa xmm5, xmm14 + shufps xmm5, xmm15, 250 + pblendw xmm6, xmm5, 0CCH + movdqa xmm5, xmm15 + punpcklqdq xmm5, xmm13 + pblendw xmm5, xmm14, 0C0H + pshufd xmm5, xmm5, 78H + punpckhdq xmm13, xmm15 + punpckldq xmm14, xmm13 + pshufd xmm15, xmm14, 1EH + movdqa xmm13, xmm6 + movdqa xmm14, xmm5 + movdqa xmm5, xmmword ptr [rsp+20H] + movdqa xmm6, xmmword ptr [rsp+40H] + jmp roundloop2 +endroundloop2: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + pxor xmm8, xmm10 + pxor xmm9, xmm11 + mov eax, r13d + cmp rdx, r15 + jne innerloop2 + movups xmmword ptr [rbx], xmm0 + movups xmmword ptr [rbx+10H], xmm1 + movups xmmword ptr [rbx+20H], xmm8 + movups xmmword ptr [rbx+30H], xmm9 + movdqa xmm0, xmmword ptr [rsp+130H] + movdqa xmm1, xmmword ptr [rsp+110H] + movdqa xmm2, xmmword ptr [rsp+120H] + movdqu xmm3, xmmword ptr [rsp+118H] + movdqu xmm4, xmmword ptr [rsp+128H] + blendvps xmm1, xmm3, xmm0 + blendvps xmm2, xmm4, xmm0 + movdqa xmmword ptr [rsp+110H], xmm1 + movdqa xmmword ptr [rsp+120H], xmm2 + add rdi, 16 + add rbx, 64 + sub rsi, 2 +final1block: + test esi, 1H + je unwind + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+10H] + movd xmm13, dword ptr [rsp+110H] + pinsrd xmm13, dword ptr [rsp+120H], 1 + pinsrd xmm13, dword ptr [BLAKE3_BLOCK_LEN], 2 + movaps xmm14, xmmword ptr [ROT8] + movaps xmm15, xmmword ptr [ROT16] + mov r8, qword ptr [rdi] + movzx eax, byte ptr [rbp+80H] + or eax, r13d + xor edx, edx +innerloop1: + mov r14d, eax + or eax, r12d + add rdx, 64 + cmp rdx, r15 + cmovne eax, r14d + movaps xmm2, xmmword ptr [BLAKE3_IV] + movaps xmm3, xmm13 + pinsrd xmm3, eax, 3 + movups xmm4, xmmword ptr [r8+rdx-40H] + movups xmm5, xmmword ptr [r8+rdx-30H] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [r8+rdx-20H] + movups xmm7, xmmword ptr [r8+rdx-10H] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 93H + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 93H + mov al, 7 +roundloop1: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 93H + pshufd xmm3, xmm3, 4EH + pshufd xmm2, xmm2, 39H + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 39H + pshufd xmm3, xmm3, 4EH + pshufd xmm2, xmm2, 93H + dec al + jz endroundloop1 + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0FH + pshufd xmm4, xmm8, 39H + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0CCH + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0C0H + pshufd xmm8, xmm8, 78H + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 1EH + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp roundloop1 +endroundloop1: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + mov eax, r13d + cmp rdx, r15 + jne innerloop1 + movups xmmword ptr [rbx], xmm0 + movups xmmword ptr [rbx+10H], xmm1 + jmp unwind +_blake3_hash_many_sse41 ENDP +blake3_hash_many_sse41 ENDP + +blake3_compress_in_place_sse41 PROC +_blake3_compress_in_place_sse41 PROC + sub rsp, 120 + movdqa xmmword ptr [rsp], xmm6 + movdqa xmmword ptr [rsp+10H], xmm7 + movdqa xmmword ptr [rsp+20H], xmm8 + movdqa xmmword ptr [rsp+30H], xmm9 + movdqa xmmword ptr [rsp+40H], xmm11 + movdqa xmmword ptr [rsp+50H], xmm14 + movdqa xmmword ptr [rsp+60H], xmm15 + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+10H] + movaps xmm2, xmmword ptr [BLAKE3_IV] + movzx eax, byte ptr [rsp+0A0H] + movzx r8d, r8b + shl rax, 32 + add r8, rax + movq xmm3, r9 + movq xmm4, r8 + punpcklqdq xmm3, xmm4 + movups xmm4, xmmword ptr [rdx] + movups xmm5, xmmword ptr [rdx+10H] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [rdx+20H] + movups xmm7, xmmword ptr [rdx+30H] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 93H + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 93H + movaps xmm14, xmmword ptr [ROT8] + movaps xmm15, xmmword ptr [ROT16] + mov al, 7 +@@: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 93H + pshufd xmm3, xmm3, 4EH + pshufd xmm2, xmm2, 39H + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 39H + pshufd xmm3, xmm3, 4EH + pshufd xmm2, xmm2, 93H + dec al + jz @F + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0FH + pshufd xmm4, xmm8, 39H + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0CCH + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0C0H + pshufd xmm8, xmm8, 78H + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 1EH + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp @B +@@: + pxor xmm0, xmm2 + pxor xmm1, xmm3 + movups xmmword ptr [rcx], xmm0 + movups xmmword ptr [rcx+10H], xmm1 + movdqa xmm6, xmmword ptr [rsp] + movdqa xmm7, xmmword ptr [rsp+10H] + movdqa xmm8, xmmword ptr [rsp+20H] + movdqa xmm9, xmmword ptr [rsp+30H] + movdqa xmm11, xmmword ptr [rsp+40H] + movdqa xmm14, xmmword ptr [rsp+50H] + movdqa xmm15, xmmword ptr [rsp+60H] + add rsp, 120 + ret +_blake3_compress_in_place_sse41 ENDP +blake3_compress_in_place_sse41 ENDP + +ALIGN 16 +blake3_compress_xof_sse41 PROC +_blake3_compress_xof_sse41 PROC + sub rsp, 120 + movdqa xmmword ptr [rsp], xmm6 + movdqa xmmword ptr [rsp+10H], xmm7 + movdqa xmmword ptr [rsp+20H], xmm8 + movdqa xmmword ptr [rsp+30H], xmm9 + movdqa xmmword ptr [rsp+40H], xmm11 + movdqa xmmword ptr [rsp+50H], xmm14 + movdqa xmmword ptr [rsp+60H], xmm15 + movups xmm0, xmmword ptr [rcx] + movups xmm1, xmmword ptr [rcx+10H] + movaps xmm2, xmmword ptr [BLAKE3_IV] + movzx eax, byte ptr [rsp+0A0H] + movzx r8d, r8b + mov r10, qword ptr [rsp+0A8H] + shl rax, 32 + add r8, rax + movq xmm3, r9 + movq xmm4, r8 + punpcklqdq xmm3, xmm4 + movups xmm4, xmmword ptr [rdx] + movups xmm5, xmmword ptr [rdx+10H] + movaps xmm8, xmm4 + shufps xmm4, xmm5, 136 + shufps xmm8, xmm5, 221 + movaps xmm5, xmm8 + movups xmm6, xmmword ptr [rdx+20H] + movups xmm7, xmmword ptr [rdx+30H] + movaps xmm8, xmm6 + shufps xmm6, xmm7, 136 + pshufd xmm6, xmm6, 93H + shufps xmm8, xmm7, 221 + pshufd xmm7, xmm8, 93H + movaps xmm14, xmmword ptr [ROT8] + movaps xmm15, xmmword ptr [ROT16] + mov al, 7 +@@: + paddd xmm0, xmm4 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm5 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 93H + pshufd xmm3, xmm3, 4EH + pshufd xmm2, xmm2, 39H + paddd xmm0, xmm6 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm15 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 20 + psrld xmm11, 12 + por xmm1, xmm11 + paddd xmm0, xmm7 + paddd xmm0, xmm1 + pxor xmm3, xmm0 + pshufb xmm3, xmm14 + paddd xmm2, xmm3 + pxor xmm1, xmm2 + movdqa xmm11, xmm1 + pslld xmm1, 25 + psrld xmm11, 7 + por xmm1, xmm11 + pshufd xmm0, xmm0, 39H + pshufd xmm3, xmm3, 4EH + pshufd xmm2, xmm2, 93H + dec al + jz @F + movdqa xmm8, xmm4 + shufps xmm8, xmm5, 214 + pshufd xmm9, xmm4, 0FH + pshufd xmm4, xmm8, 39H + movdqa xmm8, xmm6 + shufps xmm8, xmm7, 250 + pblendw xmm9, xmm8, 0CCH + movdqa xmm8, xmm7 + punpcklqdq xmm8, xmm5 + pblendw xmm8, xmm6, 0C0H + pshufd xmm8, xmm8, 78H + punpckhdq xmm5, xmm7 + punpckldq xmm6, xmm5 + pshufd xmm7, xmm6, 1EH + movdqa xmm5, xmm9 + movdqa xmm6, xmm8 + jmp @B +@@: + movdqu xmm4, xmmword ptr [rcx] + movdqu xmm5, xmmword ptr [rcx+10H] + pxor xmm0, xmm2 + pxor xmm1, xmm3 + pxor xmm2, xmm4 + pxor xmm3, xmm5 + movups xmmword ptr [r10], xmm0 + movups xmmword ptr [r10+10H], xmm1 + movups xmmword ptr [r10+20H], xmm2 + movups xmmword ptr [r10+30H], xmm3 + movdqa xmm6, xmmword ptr [rsp] + movdqa xmm7, xmmword ptr [rsp+10H] + movdqa xmm8, xmmword ptr [rsp+20H] + movdqa xmm9, xmmword ptr [rsp+30H] + movdqa xmm11, xmmword ptr [rsp+40H] + movdqa xmm14, xmmword ptr [rsp+50H] + movdqa xmm15, xmmword ptr [rsp+60H] + add rsp, 120 + ret +_blake3_compress_xof_sse41 ENDP +blake3_compress_xof_sse41 ENDP + +_TEXT ENDS + + +_RDATA SEGMENT READONLY PAGE ALIAS(".rdata") 'CONST' +ALIGN 64 +BLAKE3_IV: + dd 6A09E667H, 0BB67AE85H, 3C6EF372H, 0A54FF53AH + +ADD0: + dd 0, 1, 2, 3 + +ADD1: + dd 4 dup (4) + +BLAKE3_IV_0: + dd 4 dup (6A09E667H) + +BLAKE3_IV_1: + dd 4 dup (0BB67AE85H) + +BLAKE3_IV_2: + dd 4 dup (3C6EF372H) + +BLAKE3_IV_3: + dd 4 dup (0A54FF53AH) + +BLAKE3_BLOCK_LEN: + dd 4 dup (64) + +ROT16: + db 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13 + +ROT8: + db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 + +CMP_MSB_MASK: + dd 8 dup(80000000H) + +_RDATA ENDS +END + diff --git a/src/Native/libmultihash/blake3/main.c b/src/Native/libmultihash/blake3/main.c new file mode 100644 index 000000000..9b8a436f3 --- /dev/null +++ b/src/Native/libmultihash/blake3/main.c @@ -0,0 +1,166 @@ +/* + * This main file is intended for testing via `make test`. It does not build in + * other settings. See README.md in this directory for examples of how to build + * C code. + */ + +#include +#include +#include +#include +#include +#include + +#include "blake3.h" +#include "blake3_impl.h" + +#define HASH_MODE 0 +#define KEYED_HASH_MODE 1 +#define DERIVE_KEY_MODE 2 + +static void hex_char_value(uint8_t c, uint8_t *value, bool *valid) { + if ('0' <= c && c <= '9') { + *value = c - '0'; + *valid = true; + } else if ('a' <= c && c <= 'f') { + *value = 10 + c - 'a'; + *valid = true; + } else { + *valid = false; + } +} + +static int parse_key(char *hex_key, uint8_t out[BLAKE3_KEY_LEN]) { + size_t hex_len = strlen(hex_key); + if (hex_len != 64) { + fprintf(stderr, "Expected a 64-char hexadecimal key, got %zu chars.\n", + hex_len); + return 1; + } + for (size_t i = 0; i < 64; i++) { + uint8_t value; + bool valid; + hex_char_value(hex_key[i], &value, &valid); + if (!valid) { + fprintf(stderr, "Invalid hex char.\n"); + return 1; + } + if (i % 2 == 0) { + out[i / 2] = 0; + value <<= 4; + } + out[i / 2] += value; + } + return 0; +} + +/* A little repetition here */ +enum cpu_feature { + SSE2 = 1 << 0, + SSSE3 = 1 << 1, + SSE41 = 1 << 2, + AVX = 1 << 3, + AVX2 = 1 << 4, + AVX512F = 1 << 5, + AVX512VL = 1 << 6, + /* ... */ + UNDEFINED = 1 << 30 +}; + +extern enum cpu_feature g_cpu_features; +enum cpu_feature get_cpu_features(); + +int main(int argc, char **argv) { + size_t out_len = BLAKE3_OUT_LEN; + uint8_t key[BLAKE3_KEY_LEN]; + char *context = ""; + uint8_t mode = HASH_MODE; + while (argc > 1) { + if (argc <= 2) { + fprintf(stderr, "Odd number of arguments.\n"); + return 1; + } + if (strcmp("--length", argv[1]) == 0) { + char *endptr = NULL; + errno = 0; + unsigned long long out_len_ll = strtoull(argv[2], &endptr, 10); + if (errno != 0 || out_len > SIZE_MAX || endptr == argv[2] || + *endptr != 0) { + fprintf(stderr, "Bad length argument.\n"); + return 1; + } + out_len = (size_t)out_len_ll; + } else if (strcmp("--keyed", argv[1]) == 0) { + mode = KEYED_HASH_MODE; + int ret = parse_key(argv[2], key); + if (ret != 0) { + return ret; + } + } else if (strcmp("--derive-key", argv[1]) == 0) { + mode = DERIVE_KEY_MODE; + context = argv[2]; + } else { + fprintf(stderr, "Unknown flag.\n"); + return 1; + } + argc -= 2; + argv += 2; + } + + /* + * We're going to hash the input multiple times, so we need to buffer it all. + * This is just for test cases, so go ahead and assume that the input is less + * than 1 MiB. + */ + size_t buf_capacity = 1 << 20; + uint8_t *buf = malloc(buf_capacity); + assert(buf != NULL); + size_t buf_len = 0; + while (1) { + size_t n = fread(&buf[buf_len], 1, buf_capacity - buf_len, stdin); + if (n == 0) { + break; + } + buf_len += n; + assert(buf_len < buf_capacity); + } + + const int mask = get_cpu_features(); + int feature = 0; + do { + fprintf(stderr, "Testing 0x%08X\n", feature); + g_cpu_features = feature; + blake3_hasher hasher; + switch (mode) { + case HASH_MODE: + blake3_hasher_init(&hasher); + break; + case KEYED_HASH_MODE: + blake3_hasher_init_keyed(&hasher, key); + break; + case DERIVE_KEY_MODE: + blake3_hasher_init_derive_key(&hasher, context); + break; + default: + abort(); + } + + blake3_hasher_update(&hasher, buf, buf_len); + + /* TODO: An incremental output reader API to avoid this allocation. */ + uint8_t *out = malloc(out_len); + if (out_len > 0 && out == NULL) { + fprintf(stderr, "malloc() failed.\n"); + return 1; + } + blake3_hasher_finalize(&hasher, out, out_len); + for (size_t i = 0; i < out_len; i++) { + printf("%02x", out[i]); + } + printf("\n"); + free(out); + feature = (feature - mask) & mask; + } while (feature != 0); + free(buf); + return 0; +} diff --git a/src/Native/libmultihash/blake3/makefile b/src/Native/libmultihash/blake3/makefile new file mode 100644 index 000000000..374c91ced --- /dev/null +++ b/src/Native/libmultihash/blake3/makefile @@ -0,0 +1,60 @@ +CC=gcc +CFLAGS=-O3 -Wall -Wextra -std=c11 -pedantic +TARGETS= +ASM_TARGETS= +EXTRAFLAGS= + +ifdef BLAKE3_NO_SSE41 +EXTRAFLAGS += -DBLAKE3_NO_SSE41 +else +TARGETS += blake3_sse41.o +ASM_TARGETS += blake3_sse41_x86-64_unix.S +endif + +ifdef BLAKE3_NO_AVX2 +EXTRAFLAGS += -DBLAKE3_NO_AVX2 +else +TARGETS += blake3_avx2.o +ASM_TARGETS += blake3_avx2_x86-64_unix.S +endif + +ifdef BLAKE3_NO_AVX512 +EXTRAFLAGS += -DBLAKE3_NO_AVX512 +else +TARGETS += blake3_avx512.o +ASM_TARGETS += blake3_avx512_x86-64_unix.S +endif + +ifdef BLAKE3_USE_NEON +EXTRAFLAGS += -DBLAKE3_USE_NEON +TARGETS += blake3_neon.o +endif + +all: blake3.c blake3_dispatch.c blake3_portable.c main.c $(TARGETS) + $(CC) $(CFLAGS) $(EXTRAFLAGS) $^ -o $(NAME) + +blake3_sse41.o: blake3_sse41.c + $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ -msse4.1 + +blake3_avx2.o: blake3_avx2.c + $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ -mavx2 + +blake3_avx512.o: blake3_avx512.c + $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ -mavx512f -mavx512vl + +blake3_neon.o: blake3_neon.c + $(CC) $(CFLAGS) $(EXTRAFLAGS) -c $^ -o $@ + +test: CFLAGS += -DBLAKE3_TESTING -fsanitize=address,undefined +test: all + ./test.py + +asm: blake3.c blake3_dispatch.c blake3_portable.c main.c $(ASM_TARGETS) + $(CC) $(CFLAGS) $(EXTRAFLAGS) $^ -o $(NAME) + +test_asm: CFLAGS += -DBLAKE3_TESTING -fsanitize=address,undefined +test_asm: asm + ./test.py + +clean: + rm -f $(NAME) *.o diff --git a/src/Native/libmultihash/blake3/test.py b/src/Native/libmultihash/blake3/test.py new file mode 100644 index 000000000..b0b192950 --- /dev/null +++ b/src/Native/libmultihash/blake3/test.py @@ -0,0 +1,97 @@ +#! /usr/bin/env python3 + +from binascii import hexlify +import json +from os import path +import subprocess + +HERE = path.dirname(__file__) +TEST_VECTORS_PATH = path.join(HERE, "..", "test_vectors", "test_vectors.json") +TEST_VECTORS = json.load(open(TEST_VECTORS_PATH)) + + +def run_blake3(args, input): + output = subprocess.run([path.join(HERE, "blake3")] + args, + input=input, + stdout=subprocess.PIPE, + check=True) + return output.stdout.decode().strip() + + +# Fill the input with a repeating byte pattern. We use a cycle length of 251, +# because that's the largets prime number less than 256. This makes it unlikely +# to swapping any two adjacent input blocks or chunks will give the same +# answer. +def make_test_input(length): + i = 0 + buf = bytearray() + while len(buf) < length: + buf.append(i) + i = (i + 1) % 251 + return buf + + +def main(): + for case in TEST_VECTORS["cases"]: + input_len = case["input_len"] + input = make_test_input(input_len) + hex_key = hexlify(TEST_VECTORS["key"].encode()) + context_string = TEST_VECTORS["context_string"] + expected_hash_xof = case["hash"] + expected_hash = expected_hash_xof[:64] + expected_keyed_hash_xof = case["keyed_hash"] + expected_keyed_hash = expected_keyed_hash_xof[:64] + expected_derive_key_xof = case["derive_key"] + expected_derive_key = expected_derive_key_xof[:64] + + # Test the default hash. + test_hash = run_blake3([], input) + for line in test_hash.splitlines(): + assert expected_hash == line, \ + "hash({}): {} != {}".format(input_len, expected_hash, line) + + # Test the extended hash. + xof_len = len(expected_hash_xof) // 2 + test_hash_xof = run_blake3(["--length", str(xof_len)], input) + for line in test_hash_xof.splitlines(): + assert expected_hash_xof == line, \ + "hash_xof({}): {} != {}".format( + input_len, expected_hash_xof, line) + + # Test the default keyed hash. + test_keyed_hash = run_blake3(["--keyed", hex_key], input) + for line in test_keyed_hash.splitlines(): + assert expected_keyed_hash == line, \ + "keyed_hash({}): {} != {}".format( + input_len, expected_keyed_hash, line) + + # Test the extended keyed hash. + xof_len = len(expected_keyed_hash_xof) // 2 + test_keyed_hash_xof = run_blake3( + ["--keyed", hex_key, "--length", + str(xof_len)], input) + for line in test_keyed_hash_xof.splitlines(): + assert expected_keyed_hash_xof == line, \ + "keyed_hash_xof({}): {} != {}".format( + input_len, expected_keyed_hash_xof, line) + + # Test the default derive key. + test_derive_key = run_blake3(["--derive-key", context_string], input) + for line in test_derive_key.splitlines(): + assert expected_derive_key == line, \ + "derive_key({}): {} != {}".format( + input_len, expected_derive_key, line) + + # Test the extended derive key. + xof_len = len(expected_derive_key_xof) // 2 + test_derive_key_xof = run_blake3( + ["--derive-key", context_string, "--length", + str(xof_len)], input) + for line in test_derive_key_xof.splitlines(): + assert expected_derive_key_xof == line, \ + "derive_key_xof({}): {} != {}".format( + input_len, expected_derive_key_xof, line) + + +if __name__ == "__main__": + main() diff --git a/src/Native/libmultihash/exports.cpp b/src/Native/libmultihash/exports.cpp index 56ff95cea..6a71420a0 100644 --- a/src/Native/libmultihash/exports.cpp +++ b/src/Native/libmultihash/exports.cpp @@ -15,6 +15,7 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "allium.h" #include "bcrypt.h" #include "keccak.h" #include "quark.h" @@ -22,6 +23,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "scryptn.h" #include "neoscrypt.h" #include "skein.h" +#include "skein2.h" #include "x11.h" #include "groestl.h" #include "blake.h" @@ -57,6 +59,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "equi/equihashverify.h" #include "heavyhash/heavyhash.h" #include "minotaur/minotaurx.h" +#include "skydoge.h" +#include "yescrypt/yescrypt.h" +#include "yespower/yespower.h" #ifdef _WIN32 #include "blake2/ref/blake2.h" @@ -64,6 +69,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "blake2/sse/blake2.h" #endif +#include "blake3/blake3.h" + #ifdef _WIN32 #define MODULE_API __declspec(dllexport) #else @@ -157,6 +164,11 @@ extern "C" MODULE_API void skein_export(const char* input, char* output, uint32_ skein_hash(input, output, input_len); } +extern "C" MODULE_API void skein2_export(const char *input, char *output, uint32_t input_len) +{ + skein2_hash(input, output, input_len); +} + extern "C" MODULE_API void groestl_export(const char* input, char* output, uint32_t input_len) { groestl_hash(input, output, input_len); @@ -182,6 +194,11 @@ extern "C" MODULE_API void blake2b_export(const char* input, char* output, uint3 blake2b(output, output_len == -1 ? BLAKE2B_OUTBYTES : output_len, input, input_len, NULL, 0); } +extern "C" MODULE_API void blake3_export(const char* input, char* output, uint32_t input_length) +{ + blake3_hash(input, output, input_length); +} + extern "C" MODULE_API void dcrypt_export(const char* input, char* output, uint32_t input_len) { dcrypt_hash(input, output, input_len); @@ -338,4 +355,64 @@ extern "C" MODULE_API bool equihash_verify_96_5_export(const char* header, int h extern "C" MODULE_API void minotaurx_export(const char* input, char* output) { minotaurx_hash(input, output); +} + +extern "C" MODULE_API void skydoge_export(const char *input, char *output, uint32_t input_len) +{ + skydoge_hash(input, output, input_len); +} + +extern "C" MODULE_API void yescrypt_export(const char *input, char *output, uint32_t input_len) +{ + yescrypt_hash(input, output, input_len); +} + +extern "C" MODULE_API void yescryptR8_export(const char *input, char *output, uint32_t input_len) +{ + yescryptR8_hash(input, output, input_len); +} + +extern "C" MODULE_API void yescryptR16_export(const char *input, char *output, uint32_t input_len) +{ + yescryptR16_hash(input, output, input_len); +} + +extern "C" MODULE_API void yescryptR32_export(const char *input, char *output, uint32_t input_len) +{ + yescryptR32_hash(input, output, input_len); +} + +extern "C" MODULE_API void cpupower_export(const char *input, char *output, uint32_t input_len) +{ + cpupower_hash(input, output, input_len); +} + +extern "C" MODULE_API void power2b_export(const char *input, char *output, uint32_t input_len) +{ + power2b_hash(input, output, input_len); +} + +extern "C" MODULE_API void yespower_export(const char *input, char *output, uint32_t input_len) +{ + yespower_hash(input, output, input_len); +} + +extern "C" MODULE_API void yespowerIC_export(const char *input, char *output, uint32_t input_len) +{ + yespowerIC_hash(input, output, input_len); +} + +extern "C" MODULE_API void yespowerR16_export(const char *input, char *output, uint32_t input_len) +{ + yespowerR16_hash(input, output, input_len); +} + +extern "C" MODULE_API void yespowerTIDE_export(const char *input, char *output, uint32_t input_len) +{ + yespowerTIDE_hash(input, output, input_len); +} + +extern "C" MODULE_API void allium_export(const char *input, char *output, uint32_t input_len) +{ + allium_hash(input, output, input_len); } \ No newline at end of file diff --git a/src/Native/libmultihash/libmultihash.vcxproj b/src/Native/libmultihash/libmultihash.vcxproj index 056fc83b1..8abcb4800 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj +++ b/src/Native/libmultihash/libmultihash.vcxproj @@ -168,10 +168,13 @@ + + + @@ -246,12 +249,22 @@ + + + + + + + + + + @@ -270,6 +283,7 @@ + @@ -278,6 +292,18 @@ + + + + + + + + + + + + @@ -347,10 +373,20 @@ + + + + + + + + + + diff --git a/src/Native/libmultihash/libmultihash.vcxproj.filters b/src/Native/libmultihash/libmultihash.vcxproj.filters index 55d1c6f3e..c8384e7d4 100644 --- a/src/Native/libmultihash/libmultihash.vcxproj.filters +++ b/src/Native/libmultihash/libmultihash.vcxproj.filters @@ -17,6 +17,9 @@ Header Files + + Header Files + Header Files @@ -80,6 +83,12 @@ Header Files + + Header Files + + + Header Files + Header Files @@ -272,12 +281,42 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + Header Files Header Files + + Header Files + + + Header Files + Header Files @@ -325,6 +364,9 @@ Source Files + + Source Files + Source Files @@ -382,6 +424,12 @@ Source Files + + Source Files + + + Source Files + Source Files @@ -553,6 +601,30 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + Source Files @@ -571,6 +643,42 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + Source Files diff --git a/src/Native/libmultihash/minotaur/crypto/sha256.c b/src/Native/libmultihash/minotaur/crypto/sha256.c index 4981547de..781a1a55a 100644 --- a/src/Native/libmultihash/minotaur/crypto/sha256.c +++ b/src/Native/libmultihash/minotaur/crypto/sha256.c @@ -521,12 +521,12 @@ SHA256_Pad_Almost(SHA256_CTX * ctx, uint8_t len[8], } /** - * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * YESPOWER_MINOTAUR_PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). */ void -PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, +YESPOWER_MINOTAUR_PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) { HMAC_SHA256_CTX Phctx, PShctx, hctx; diff --git a/src/Native/libmultihash/minotaur/crypto/sha256.h b/src/Native/libmultihash/minotaur/crypto/sha256.h index 4b9099123..8249ca23b 100644 --- a/src/Native/libmultihash/minotaur/crypto/sha256.h +++ b/src/Native/libmultihash/minotaur/crypto/sha256.h @@ -38,16 +38,16 @@ extern "C" { * Use #defines in order to avoid namespace collisions with anyone else's * SHA256 code (e.g., the code in OpenSSL). */ -#define SHA256_Init libcperciva_SHA256_Init -#define SHA256_Update libcperciva_SHA256_Update -#define SHA256_Final libcperciva_SHA256_Final -#define SHA256_Buf libcperciva_SHA256_Buf -#define SHA256_CTX libcperciva_SHA256_CTX -#define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init -#define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update -#define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final -#define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf -#define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX +#define SHA256_Init libcperciva_SHA256_MINOTAUR_Init +#define SHA256_Update libcperciva_SHA256_MINOTAUR_Update +#define SHA256_Final libcperciva_SHA256_MINOTAUR_Final +#define SHA256_Buf libcperciva_SHA256_MINOTAUR_Buf +#define SHA256_CTX libcperciva_SHA256_MINOTAUR_CTX +#define HMAC_SHA256_Init libcperciva_HMAC_SHA256_MINOTAUR_Init +#define HMAC_SHA256_Update libcperciva_HMAC_SHA256_MINOTAUR_Update +#define HMAC_SHA256_Final libcperciva_HMAC_SHA256_MINOTAUR_Final +#define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_MINOTAUR_Buf +#define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_MINOTAUR_CTX /* Context structure for SHA256 operations. */ typedef struct { @@ -115,11 +115,11 @@ void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *); void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]); /** - * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * YESPOWER_MINOTAUR_PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). */ -void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, +void YESPOWER_MINOTAUR_PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, uint8_t *, size_t); #ifdef __cplusplus diff --git a/src/Native/libmultihash/minotaur/crypto/yespower.c b/src/Native/libmultihash/minotaur/crypto/yespower.c index e2ca167c7..bb83ca150 100644 --- a/src/Native/libmultihash/minotaur/crypto/yespower.c +++ b/src/Native/libmultihash/minotaur/crypto/yespower.c @@ -107,7 +107,7 @@ #undef HUGEPAGE_SIZE #endif -static void *alloc_region(yespower_region_t *region, size_t size) +static void *alloc_region(yespower_minotaur_region_t *region, size_t size) { size_t base_size = size; uint8_t *base, *aligned; @@ -163,13 +163,13 @@ static void *alloc_region(yespower_region_t *region, size_t size) return aligned; } -static inline void init_region(yespower_region_t *region) +static inline void init_region(yespower_minotaur_region_t *region) { region->base = region->aligned = NULL; region->base_size = region->aligned_size = 0; } -static int free_region(yespower_region_t *region) +static int free_region(yespower_minotaur_region_t *region) { if (region->base) { #ifdef MAP_ANON @@ -1102,19 +1102,19 @@ static void smix(uint8_t *B, size_t r, uint32_t N, #undef smix /** - * yespower(local, src, srclen, params, dst): - * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * yespower_minotaur(local, src, srclen, params, dst): + * Compute yespower_minotaur(src[0 .. srclen - 1], N, r), to be checked for "< target". * local is the thread-local data structure, allowing to preserve and reuse a * memory allocation across calls, thereby reducing its overhead. * * Return 0 on success; or -1 on error. */ -int yespower(yespower_local_t *local, +int yespower_minotaur(yespower_minotaur_local_t *local, const uint8_t *src, size_t srclen, - const yespower_params_t *params, - yespower_binary_t *dst) + const yespower_minotaur_params_t *params, + yespower_minotaur_binary_t *dst) { - yespower_version_t version = params->version; + yespower_minotaur_version_t version = params->version; uint32_t N = params->N; uint32_t r = params->r; const uint8_t *pers = params->pers; @@ -1164,11 +1164,11 @@ int yespower(yespower_local_t *local, SHA256_Buf(src, srclen, sha256); if (version == YESPOWER_0_5) { - PBKDF2_SHA256(sha256, sizeof(sha256), src, srclen, 1, + YESPOWER_MINOTAUR_PBKDF2_SHA256(sha256, sizeof(sha256), src, srclen, 1, B, B_size); memcpy(sha256, B, sizeof(sha256)); smix(B, r, N, V, XY, &ctx); - PBKDF2_SHA256(sha256, sizeof(sha256), B, B_size, 1, + YESPOWER_MINOTAUR_PBKDF2_SHA256(sha256, sizeof(sha256), B, B_size, 1, (uint8_t *)dst, sizeof(*dst)); if (pers) { @@ -1187,7 +1187,7 @@ int yespower(yespower_local_t *local, srclen = 0; } - PBKDF2_SHA256(sha256, sizeof(sha256), src, srclen, 1, B, 128); + YESPOWER_MINOTAUR_PBKDF2_SHA256(sha256, sizeof(sha256), src, srclen, 1, B, 128); memcpy(sha256, B, sizeof(sha256)); smix_1_0(B, r, N, V, XY, &ctx); HMAC_SHA256_Buf(B + B_size - 64, 64, @@ -1222,33 +1222,33 @@ int yespower(yespower_local_t *local, #endif /** - * yespower_tls(src, srclen, params, dst): - * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * yespower_minotaur_tls(src, srclen, params, dst): + * Compute yespower_minotaur(src[0 .. srclen - 1], N, r), to be checked for "< target". * The memory allocation is maintained internally using thread-local storage. * * Return 0 on success; or -1 on error. */ -int yespower_tls(const uint8_t *src, size_t srclen, - const yespower_params_t *params, yespower_binary_t *dst) +int yespower_minotaur_tls(const uint8_t *src, size_t srclen, + const yespower_minotaur_params_t *params, yespower_minotaur_binary_t *dst) { static thread_local int initialized = 0; - static thread_local yespower_local_t local; + static thread_local yespower_minotaur_local_t local; if (!initialized) { init_region(&local); initialized = 1; } - return yespower(&local, src, srclen, params, dst); + return yespower_minotaur(&local, src, srclen, params, dst); } -int yespower_init_local(yespower_local_t *local) +int yespower_minotaur_init_local(yespower_minotaur_local_t *local) { init_region(local); return 0; } -int yespower_free_local(yespower_local_t *local) +int yespower_minotaur_free_local(yespower_minotaur_local_t *local) { return free_region(local); } diff --git a/src/Native/libmultihash/minotaur/crypto/yespower.h b/src/Native/libmultihash/minotaur/crypto/yespower.h index 55c36ce9f..aa002dda2 100644 --- a/src/Native/libmultihash/minotaur/crypto/yespower.h +++ b/src/Native/libmultihash/minotaur/crypto/yespower.h @@ -39,53 +39,53 @@ extern "C" { /** * Internal type used by the memory allocator. Please do not use it directly. - * Use yespower_local_t instead. + * Use yespower_minotaur_local_t instead. */ typedef struct { void *base, *aligned; size_t base_size, aligned_size; -} yespower_region_t; +} yespower_minotaur_region_t; /** * Type for thread-local (RAM) data structure. */ -typedef yespower_region_t yespower_local_t; +typedef yespower_minotaur_region_t yespower_minotaur_local_t; /* - * Type for yespower algorithm version numbers. + * Type for yespower_minotaur algorithm version numbers. */ -typedef enum { YESPOWER_0_5 = 5, YESPOWER_1_0 = 10 } yespower_version_t; +typedef enum { YESPOWER_0_5 = 5, YESPOWER_1_0 = 10 } yespower_minotaur_version_t; /** - * yespower parameters combined into one struct. + * yespower_minotaur parameters combined into one struct. */ typedef struct { - yespower_version_t version; + yespower_minotaur_version_t version; uint32_t N, r; const uint8_t *pers; size_t perslen; -} yespower_params_t; +} yespower_minotaur_params_t; /** - * A 256-bit yespower hash. + * A 256-bit yespower_minotaur hash. */ typedef struct { unsigned char uc[32]; -} yespower_binary_t; +} yespower_minotaur_binary_t; /** - * yespower_init_local(local): + * yespower_minotaur_init_local(local): * Initialize the thread-local (RAM) data structure. Actual memory allocation - * is currently fully postponed until a call to yespower(). + * is currently fully postponed until a call to yespower_minotaur(). * * Return 0 on success; or -1 on error. * * MT-safe as long as local is local to the thread. */ -extern int yespower_init_local(yespower_local_t *local); +extern int yespower_minotaur_init_local(yespower_minotaur_local_t *local); /** - * yespower_free_local(local): + * yespower_minotaur_free_local(local): * Free memory that may have been allocated for an initialized thread-local * (RAM) data structure. * @@ -93,35 +93,35 @@ extern int yespower_init_local(yespower_local_t *local); * * MT-safe as long as local is local to the thread. */ -extern int yespower_free_local(yespower_local_t *local); +extern int yespower_minotaur_free_local(yespower_minotaur_local_t *local); /** - * yespower(local, src, srclen, params, dst): - * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * yespower_minotaur(local, src, srclen, params, dst): + * Compute yespower_minotaur(src[0 .. srclen - 1], N, r), to be checked for "< target". * local is the thread-local data structure, allowing to preserve and reuse a * memory allocation across calls, thereby reducing processing overhead. * * Return 0 on success; or -1 on error. * - * local must be initialized with yespower_init_local(). + * local must be initialized with yespower_minotaur_init_local(). * * MT-safe as long as local and dst are local to the thread. */ -extern int yespower(yespower_local_t *local, +extern int yespower_minotaur(yespower_minotaur_local_t *local, const uint8_t *src, size_t srclen, - const yespower_params_t *params, yespower_binary_t *dst); + const yespower_minotaur_params_t *params, yespower_minotaur_binary_t *dst); /** - * yespower_tls(src, srclen, params, dst): - * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * yespower_minotaur_tls(src, srclen, params, dst): + * Compute yespower_minotaur(src[0 .. srclen - 1], N, r), to be checked for "< target". * The memory allocation is maintained internally using thread-local storage. * * Return 0 on success; or -1 on error. * * MT-safe as long as dst is local to the thread. */ -extern int yespower_tls(const uint8_t *src, size_t srclen, - const yespower_params_t *params, yespower_binary_t *dst); +extern int yespower_minotaur_tls(const uint8_t *src, size_t srclen, + const yespower_minotaur_params_t *params, yespower_minotaur_binary_t *dst); #ifdef __cplusplus } diff --git a/src/Native/libmultihash/minotaur/minotaurx.c b/src/Native/libmultihash/minotaur/minotaurx.c index 2f3484559..00b4285f7 100644 --- a/src/Native/libmultihash/minotaur/minotaurx.c +++ b/src/Native/libmultihash/minotaur/minotaurx.c @@ -32,7 +32,7 @@ // Config #define MINOTAUR_ALGO_COUNT 16 -static const yespower_params_t yespower_params = {YESPOWER_1_0, 2048, 8, "et in arcadia ego", 17}; +static const yespower_minotaur_params_t yespower_minotaur_params = {YESPOWER_1_0, 2048, 8, "et in arcadia ego", 17}; typedef struct TortureNode TortureNode; typedef struct TortureGarden TortureGarden; @@ -158,7 +158,7 @@ void get_hash(void *output, const void *input, TortureGarden *garden, unsigned i break; // NB: The CPU-hard gate must be case MINOTAUR_ALGO_COUNT. case 16: - yespower_tls(input, 64, &yespower_params, (yespower_binary_t*)hash); + yespower_minotaur_tls(input, 64, &yespower_minotaur_params, (yespower_minotaur_binary_t*)hash); } // Output the hash diff --git a/src/Native/libmultihash/skein2.c b/src/Native/libmultihash/skein2.c new file mode 100644 index 000000000..01d5056b6 --- /dev/null +++ b/src/Native/libmultihash/skein2.c @@ -0,0 +1,24 @@ +#include "skein2.h" +#include +#include +#include +#include + +#include "sha3/sph_skein.h" +#include "sha256.h" + +#include + +void skein2_hash(const char *input, char *output, uint32_t len) +{ + char temp[64]; + + sph_skein512_context ctx_skien; + sph_skein512_init(&ctx_skien); + sph_skein512(&ctx_skien, input, len); + sph_skein512_close(&ctx_skien, &temp); + + sph_skein512_init(&ctx_skien); + sph_skein512(&ctx_skien, &temp, 64); + sph_skein512_close(&ctx_skien, &output[0]); +} \ No newline at end of file diff --git a/src/Native/libmultihash/skein2.h b/src/Native/libmultihash/skein2.h new file mode 100644 index 000000000..b010c5254 --- /dev/null +++ b/src/Native/libmultihash/skein2.h @@ -0,0 +1,17 @@ +#ifndef SKEIN2_H +#define SKEIN2_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + + void skein2_hash(const char *input, char *output, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/Native/libmultihash/skydoge.c b/src/Native/libmultihash/skydoge.c new file mode 100644 index 000000000..bb486e6ab --- /dev/null +++ b/src/Native/libmultihash/skydoge.c @@ -0,0 +1,133 @@ +#include +#include +#include + +#include "sha3/sph_blake.h" +#include "sha3/sph_bmw.h" +#include "sha3/sph_groestl.h" +#include "sha3/sph_skein.h" +#include "sha3/sph_jh.h" +#include "sha3/sph_keccak.h" +#include "sha3/sph_luffa.h" +#include "sha3/sph_cubehash.h" +#include "sha3/sph_shavite.h" +#include "sha3/sph_simd.h" +#include "sha3/sph_echo.h" +#include "sha3/sph_hamsi.h" +#include "sha3/sph_fugue.h" +#include "sha3/sph_shabal.h" +#include "sha3/sph_whirlpool.h" +#include "sha3/sph_sha2.h" +#include "sha3/sph_haval.h" + +#define _ALIGN(x) __attribute__ ((aligned(x))) + +void skydoge_hash(const char* input, char* output, uint32_t len) +{ + sph_blake512_context ctx_blake; + sph_bmw512_context ctx_bmw; + sph_groestl512_context ctx_groestl; + sph_skein512_context ctx_skein; + sph_jh512_context ctx_jh; + sph_keccak512_context ctx_keccak; + sph_luffa512_context ctx_luffa1; + sph_cubehash512_context ctx_cubehash1; + sph_shavite512_context ctx_shavite1; + sph_simd512_context ctx_simd1; + sph_echo512_context ctx_echo1; + sph_hamsi512_context ctx_hamsi1; + sph_fugue512_context ctx_fugue1; + sph_shabal512_context ctx_shabal1; + sph_whirlpool_context ctx_whirlpool1; + sph_sha512_context ctx_sha512; + sph_sha256_context ctx_sha; + sph_haval256_5_context ctx_haval; + + uint32_t hash[16]; + uint32_t hashA[16]; + + sph_blake512_init(&ctx_blake); + sph_blake512 (&ctx_blake, input, len); + sph_blake512_close (&ctx_blake, hash); + + sph_skein512_init(&ctx_skein); + sph_skein512 (&ctx_skein, hash, 64); + sph_skein512_close (&ctx_skein, hash); + + sph_bmw512_init(&ctx_bmw); + sph_bmw512 (&ctx_bmw, hash, 64); + sph_bmw512_close(&ctx_bmw, hash); + + sph_groestl512_init(&ctx_groestl); + sph_groestl512 (&ctx_groestl, hash, 64); + sph_groestl512_close(&ctx_groestl, hash); + + sph_jh512_init(&ctx_jh); + sph_jh512 (&ctx_jh, hash, 64); + sph_jh512_close(&ctx_jh, hash); + + sph_luffa512_init (&ctx_luffa1); + sph_luffa512 (&ctx_luffa1, hash, 64); + sph_luffa512_close (&ctx_luffa1, hash); + + sph_keccak512_init(&ctx_keccak); + sph_keccak512 (&ctx_keccak, hash, 64); + sph_keccak512_close(&ctx_keccak, hash); + + sph_simd512_init (&ctx_simd1); + sph_simd512 (&ctx_simd1, hash, 64); + sph_simd512_close(&ctx_simd1, hash); + + sph_echo512_init (&ctx_echo1); + sph_echo512 (&ctx_echo1, hash, 64); + sph_echo512_close(&ctx_echo1, hash); + + sph_cubehash512_init (&ctx_cubehash1); + sph_cubehash512 (&ctx_cubehash1, hash, 64); + sph_cubehash512_close(&ctx_cubehash1, hash); + + sph_shavite512_init (&ctx_shavite1); + sph_shavite512 (&ctx_shavite1, hash, 64); + sph_shavite512_close(&ctx_shavite1, hash); + + sph_hamsi512_init (&ctx_hamsi1); + sph_hamsi512 (&ctx_hamsi1, hash, 64); + sph_hamsi512_close(&ctx_hamsi1, hash); + + sph_fugue512_init (&ctx_fugue1); + sph_fugue512 (&ctx_fugue1, hash, 64); + sph_fugue512_close(&ctx_fugue1, hash); + + sph_shabal512_init (&ctx_shabal1); + sph_shabal512 (&ctx_shabal1, hash, 64); + sph_shabal512_close(&ctx_shabal1, hash); + + sph_whirlpool_init (&ctx_whirlpool1); + sph_whirlpool (&ctx_whirlpool1, hash, 64); + sph_whirlpool_close(&ctx_whirlpool1, hash); + + sph_sha512_init(&ctx_sha512); + sph_sha512(&ctx_sha512, hash, 64); + sph_sha512_close(&ctx_sha512, hash); + + sph_simd512_init (&ctx_simd1); + sph_simd512 (&ctx_simd1, hash, 64); + sph_simd512_close(&ctx_simd1, hash); + + sph_whirlpool_init (&ctx_whirlpool1); + sph_whirlpool (&ctx_whirlpool1, hash, 64); + sph_whirlpool_close(&ctx_whirlpool1, hash); + + sph_sha256_init(&ctx_sha); + sph_sha256 (&ctx_sha, hash, 64); + sph_sha256_close(&ctx_sha, hashA); + + for (int i=8;i<16;i++) + hashA[i]=0; + + sph_haval256_5_init(&ctx_haval); + sph_haval256_5(&ctx_haval, hashA, 64); + sph_haval256_5_close(&ctx_haval,hash); + + memcpy(output, hash, 32); +} diff --git a/src/Native/libmultihash/skydoge.h b/src/Native/libmultihash/skydoge.h new file mode 100644 index 000000000..2e9d9f0b3 --- /dev/null +++ b/src/Native/libmultihash/skydoge.h @@ -0,0 +1,16 @@ +#ifndef SKYDOGE_H +#define SKYDOGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void skydoge_hash(const char* input, char* output, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/Native/libmultihash/yescrypt/sha256.c b/src/Native/libmultihash/yescrypt/sha256.c new file mode 100644 index 000000000..f29de6dc3 --- /dev/null +++ b/src/Native/libmultihash/yescrypt/sha256.c @@ -0,0 +1,411 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +#include "sysendian.h" + +#include "sha256.h" + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + be32enc(dst + i * 4, src[i]); +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) + dst[i] = be32dec(src + i * 4); +} + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t * state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) + state[i] += S[i]; + + /* Clean the stack. */ + memset(W, 0, 256); + memset(S, 0, 32); + t0 = t1 = 0; +} + +static unsigned char PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX_Y * ctx) +{ + unsigned char len[8]; + uint32_t r, plen; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + r = (ctx->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + SHA256_Update_Y(ctx, PAD, (size_t)plen); + + /* Add the terminating bit-count */ + SHA256_Update_Y(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void +SHA256_Init_Y(SHA256_CTX_Y * ctx) +{ + + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +void +SHA256_Update_Y(SHA256_CTX_Y * ctx, const void *in, size_t len) +{ + uint32_t bitlen[2]; + uint32_t r; + const unsigned char *src = in; + + /* Number of bytes left in the buffer from previous updates */ + r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + bitlen[1] = ((uint32_t)len) << 3; + bitlen[0] = (uint32_t)(len >> 29); + + /* Update number of bits */ + if ((ctx->count[1] += bitlen[1]) < bitlen[1]) + ctx->count[0]++; + ctx->count[0] += bitlen[0]; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + SHA256_Transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void +SHA256_Final_Y(unsigned char digest[32], SHA256_CTX_Y * ctx) +{ + + /* Add padding */ + SHA256_Pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *)ctx, 0, sizeof(*ctx)); +} + +/* Initialize an HMAC-SHA256 operation with the given key. */ +void +HMAC_SHA256_Init_Y(HMAC_SHA256_CTX_Y * ctx, const void * _K, size_t Klen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + const unsigned char * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init_Y(&ctx->ictx); + SHA256_Update_Y(&ctx->ictx, K, Klen); + SHA256_Final_Y(khash, &ctx->ictx); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init_Y(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update_Y(&ctx->ictx, pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init_Y(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + SHA256_Update_Y(&ctx->octx, pad, 64); + + /* Clean the stack. */ + memset(khash, 0, 32); +} + +/* Add bytes to the HMAC-SHA256 operation. */ +void +HMAC_SHA256_Update_Y(HMAC_SHA256_CTX_Y * ctx, const void *in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + SHA256_Update_Y(&ctx->ictx, in, len); +} + +/* Finish an HMAC-SHA256 operation. */ +void +HMAC_SHA256_Final_Y(unsigned char digest[32], HMAC_SHA256_CTX_Y * ctx) +{ + unsigned char ihash[32]; + + /* Finish the inner SHA256 operation. */ + SHA256_Final_Y(ihash, &ctx->ictx); + + /* Feed the inner hash to the outer SHA256 operation. */ + SHA256_Update_Y(&ctx->octx, ihash, 32); + + /* Finish the outer SHA256 operation. */ + SHA256_Final_Y(digest, &ctx->octx); + + /* Clean the stack. */ + memset(ihash, 0, 32); +} + +/** + * PBKDF2_SHA256_Y(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256_Y(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX_Y PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init_Y(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update_Y(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX_Y)); + HMAC_SHA256_Update_Y(&hctx, ivec, 4); + HMAC_SHA256_Final_Y(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init_Y(&hctx, passwd, passwdlen); + HMAC_SHA256_Update_Y(&hctx, U, 32); + HMAC_SHA256_Final_Y(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX_Y)); +} \ No newline at end of file diff --git a/src/Native/libmultihash/yescrypt/sha256.h b/src/Native/libmultihash/yescrypt/sha256.h new file mode 100644 index 000000000..67e685187 --- /dev/null +++ b/src/Native/libmultihash/yescrypt/sha256.h @@ -0,0 +1,62 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256_Y.h,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include + +#include + +typedef struct SHA256Context { + uint32_t state[8]; + uint32_t count[2]; + unsigned char buf[64]; +} SHA256_CTX_Y; + +typedef struct HMAC_SHA256Context { + SHA256_CTX_Y ictx; + SHA256_CTX_Y octx; +} HMAC_SHA256_CTX_Y; + +void SHA256_Init_Y(SHA256_CTX_Y *); +void SHA256_Update_Y(SHA256_CTX_Y *, const void *, size_t); +void SHA256_Final_Y(unsigned char [32], SHA256_CTX_Y *); +void HMAC_SHA256_Init_Y(HMAC_SHA256_CTX_Y *, const void *, size_t); +void HMAC_SHA256_Update_Y(HMAC_SHA256_CTX_Y *, const void *, size_t); +void HMAC_SHA256_Final_Y(unsigned char [32], HMAC_SHA256_CTX_Y *); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ \ No newline at end of file diff --git a/src/Native/libmultihash/yescrypt/sysendian.h b/src/Native/libmultihash/yescrypt/sysendian.h new file mode 100644 index 000000000..86d3c29d2 --- /dev/null +++ b/src/Native/libmultihash/yescrypt/sysendian.h @@ -0,0 +1,124 @@ +/*- + * Copyright 2007-2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +/* If we don't have be64enc, the we have isn't usable. */ +#if !HAVE_DECL_BE64ENC +#undef HAVE_SYS_ENDIAN_H +#endif + +#ifdef HAVE_SYS_ENDIAN_H + +#include + +#else + +#include + + + +static inline uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static inline void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + + + +static inline uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[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)); +} + +static inline void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} + + +static __inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static __inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +#endif /* !HAVE_SYS_ENDIAN_H */ + +#endif /* !_SYSENDIAN_H_ */ \ No newline at end of file diff --git a/src/Native/libmultihash/yescrypt/yescrypt-opt.c b/src/Native/libmultihash/yescrypt/yescrypt-opt.c new file mode 100644 index 000000000..5dfd761b2 --- /dev/null +++ b/src/Native/libmultihash/yescrypt/yescrypt-opt.c @@ -0,0 +1,973 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include + +#include "sha256.h" +#include "sysendian.h" + +#include "yescrypt-platform.c" + +static inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static inline void +blkcpy(uint64_t * dest, const uint64_t * src, size_t count) +{ + do { + *dest++ = *src++; *dest++ = *src++; + *dest++ = *src++; *dest++ = *src++; + } while (count -= 4); +} + +static inline void +blkxor(uint64_t * dest, const uint64_t * src, size_t count) +{ + do { + *dest++ ^= *src++; *dest++ ^= *src++; + *dest++ ^= *src++; *dest++ ^= *src++; + } while (count -= 4); +} + +typedef union { + uint32_t w[16]; + uint64_t d[8]; +} salsa20_blk_t; + +static inline void +salsa20_simd_shuffle(const salsa20_blk_t * Bin, salsa20_blk_t * Bout) +{ +#define COMBINE(out, in1, in2) \ + Bout->d[out] = Bin->w[in1 * 2] | ((uint64_t)Bin->w[in2 * 2 + 1] << 32); + COMBINE(0, 0, 2) + COMBINE(1, 5, 7) + COMBINE(2, 2, 4) + COMBINE(3, 7, 1) + COMBINE(4, 4, 6) + COMBINE(5, 1, 3) + COMBINE(6, 6, 0) + COMBINE(7, 3, 5) +#undef COMBINE +} + +static inline void +salsa20_simd_unshuffle(const salsa20_blk_t * Bin, salsa20_blk_t * Bout) +{ +#define COMBINE(out, in1, in2) \ + Bout->w[out * 2] = Bin->d[in1]; \ + Bout->w[out * 2 + 1] = Bin->d[in2] >> 32; + COMBINE(0, 0, 6) + COMBINE(1, 5, 3) + COMBINE(2, 2, 0) + COMBINE(3, 7, 5) + COMBINE(4, 4, 2) + COMBINE(5, 1, 7) + COMBINE(6, 6, 4) + COMBINE(7, 3, 1) +#undef COMBINE +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint64_t B[8]) +{ + size_t i; + salsa20_blk_t X; +#define x X.w + + salsa20_simd_unshuffle((const salsa20_blk_t *)B, &X); + + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } +#undef x + + { + salsa20_blk_t Y; + salsa20_simd_shuffle(&X, &Y); + for (i = 0; i < 16; i += 4) { + ((salsa20_blk_t *)B)->w[i] += Y.w[i]; + ((salsa20_blk_t *)B)->w[i + 1] += Y.w[i + 1]; + ((salsa20_blk_t *)B)->w[i + 2] += Y.w[i + 2]; + ((salsa20_blk_t *)B)->w[i + 3] += Y.w[i + 3]; + } + } +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint64_t * Bin, uint64_t * Bout, uint64_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 8], 8); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8], 8); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4], X, 8); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8 + 8], 8); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4 + r * 8], X, 8); + } +} + +/* These are tunable */ +#define S_BITS 8 +#define S_SIMD 2 +#define S_P 4 +#define S_ROUNDS 6 + +/* Number of S-boxes. Not tunable, hard-coded in a few places. */ +#define S_N 2 + +/* Derived values. Not tunable on their own. */ +#define S_SIZE1 (1 << S_BITS) +#define S_MASK ((S_SIZE1 - 1) * S_SIMD * 8) +#define S_MASK2 (((uint64_t)S_MASK << 32) | S_MASK) +#define S_SIZE_ALL (S_N * S_SIZE1 * S_SIMD) +#define S_P_SIZE (S_P * S_SIMD) +#define S_MIN_R ((S_P * S_SIMD + 15) / 16) + +/** + * pwxform(B): + * Transform the provided block using the provided S-boxes. + */ +static void +block_pwxform(uint64_t * B, const uint64_t * S) +{ + uint64_t (*X)[S_SIMD] = (uint64_t (*)[S_SIMD])B; + const uint8_t *S0 = (const uint8_t *)S; + const uint8_t *S1 = (const uint8_t *)(S + S_SIZE1 * S_SIMD); + size_t i, j; +#if S_SIMD > 2 + size_t k; +#endif + + for (j = 0; j < S_P; j++) { + uint64_t *Xj = X[j]; + uint64_t x0 = Xj[0]; +#if S_SIMD > 1 + uint64_t x1 = Xj[1]; +#endif + + for (i = 0; i < S_ROUNDS; i++) { + uint64_t x = x0 & S_MASK2; + const uint64_t *p0, *p1; + + p0 = (const uint64_t *)(S0 + (uint32_t)x); + p1 = (const uint64_t *)(S1 + (x >> 32)); + + x0 = (uint64_t)(x0 >> 32) * (uint32_t)x0; + x0 += p0[0]; + x0 ^= p1[0]; + +#if S_SIMD > 1 + x1 = (uint64_t)(x1 >> 32) * (uint32_t)x1; + x1 += p0[1]; + x1 ^= p1[1]; +#endif + +#if S_SIMD > 2 + for (k = 2; k < S_SIMD; k++) { + x = Xj[k]; + + x = (uint64_t)(x >> 32) * (uint32_t)x; + x += p0[k]; + x ^= p1[k]; + + Xj[k] = x; + } +#endif + } + + Xj[0] = x0; +#if S_SIMD > 1 + Xj[1] = x1; +#endif + } +} + +/** + * blockmix_pwxform(Bin, Bout, S, r): + * Compute Bout = BlockMix_pwxform{salsa20/8, S, r}(Bin). The input Bin must + * be 128r bytes in length; the output Bout must also be the same size. + * + * S lacks const qualifier to match blockmix_salsa8()'s prototype, which we + * need to refer to both functions via the same function pointers. + */ +static void +blockmix_pwxform(const uint64_t * Bin, uint64_t * Bout, uint64_t * S, size_t r) +{ + size_t r1, r2, i; + + /* Convert 128-byte blocks to (S_P_SIZE * 64-bit) blocks */ + r1 = r * 128 / (S_P_SIZE * 8); + + /* X <-- B_{r1 - 1} */ + blkcpy(Bout, &Bin[(r1 - 1) * S_P_SIZE], S_P_SIZE); + + /* X <-- X \xor B_i */ + blkxor(Bout, Bin, S_P_SIZE); + + /* X <-- H'(X) */ + /* B'_i <-- X */ + block_pwxform(Bout, S); + + /* for i = 0 to r1 - 1 do */ + for (i = 1; i < r1; i++) { + /* X <-- X \xor B_i */ + blkcpy(&Bout[i * S_P_SIZE], &Bout[(i - 1) * S_P_SIZE], + S_P_SIZE); + blkxor(&Bout[i * S_P_SIZE], &Bin[i * S_P_SIZE], S_P_SIZE); + + /* X <-- H'(X) */ + /* B'_i <-- X */ + block_pwxform(&Bout[i * S_P_SIZE], S); + } + + /* Handle partial blocks */ + if (i * S_P_SIZE < r * 16) + blkcpy(&Bout[i * S_P_SIZE], &Bin[i * S_P_SIZE], + r * 16 - i * S_P_SIZE); + + i = (r1 - 1) * S_P_SIZE / 8; + /* Convert 128-byte blocks to 64-byte blocks */ + r2 = r * 2; + + /* B'_i <-- H(B'_i) */ + salsa20_8(&Bout[i * 8]); + i++; + + for (; i < r2; i++) { + /* B'_i <-- H(B'_i \xor B'_{i-1}) */ + blkxor(&Bout[i * 8], &Bout[(i - 1) * 8], 8); + salsa20_8(&Bout[i * 8]); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint64_t +integerify(const uint64_t * B, size_t r) +{ +/* + * Our 64-bit words are in host byte order, and word 6 holds the second 32-bit + * word of B_{2r-1} due to SIMD shuffling. The 64-bit value we return is also + * in host byte order, as it should be. + */ + const uint64_t * X = &B[(2 * r - 1) * 8]; + uint32_t lo = X[0]; + uint32_t hi = X[6] >> 32; + return ((uint64_t)hi << 32) + lo; +} + +/** + * smix1(B, r, N, flags, V, NROM, shared, XY, S): + * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be even and + * no smaller than 2. + */ +static void +smix1(uint64_t * B, size_t r, uint64_t N, yescrypt_flags_t flags, + uint64_t * V, uint64_t NROM, const yescrypt_shared_t * shared, + uint64_t * XY, uint64_t * S) +{ + void (*blockmix)(const uint64_t *, uint64_t *, uint64_t *, size_t) = + (S ? blockmix_pwxform : blockmix_salsa8); + const uint64_t * VROM = shared->shared1.aligned; + uint32_t VROM_mask = shared->mask1; + size_t s = 16 * r; + uint64_t * X = V; + uint64_t * Y = &XY[s]; + uint64_t * Z = S ? S : &XY[2 * s]; + uint64_t n, i, j; + size_t k; + + /* 1: X <-- B */ + /* 3: V_i <-- X */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&B[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&X[i * 8]; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + blockmix(X, Y, Z, r); + blkcpy(&V[s], Y, s); + + X = XY; + + if (NROM && (VROM_mask & 1)) { + if ((1 & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j = integerify(Y, r) & (NROM - 1); + + /* X <-- H(X \xor VROM_j) */ + blkxor(Y, &VROM[j * s], s); + } + + blockmix(Y, X, Z, r); + + /* 2: for i = 0 to N - 1 do */ + for (n = 1, i = 2; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * s], X, s); + + if ((i & (i - 1)) == 0) + n <<= 1; + + /* j <-- Wrap(Integerify(X), i) */ + j = integerify(X, r) & (n - 1); + j += i - n; + + /* X <-- X \xor V_j */ + blkxor(X, &V[j * s], s); + + /* 4: X <-- H(X) */ + blockmix(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * s], Y, s); + + j = integerify(Y, r); + if (((i + 1) & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j &= NROM - 1; + + /* X <-- H(X \xor VROM_j) */ + blkxor(Y, &VROM[j * s], s); + } else { + /* j <-- Wrap(Integerify(X), i) */ + j &= n - 1; + j += i + 1 - n; + + /* X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * s], s); + } + + blockmix(Y, X, Z, r); + } + } else { + yescrypt_flags_t rw = flags & YESCRYPT_RW; + + /* 4: X <-- H(X) */ + blockmix(Y, X, Z, r); + + /* 2: for i = 0 to N - 1 do */ + for (n = 1, i = 2; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * s], X, s); + + if (rw) { + if ((i & (i - 1)) == 0) + n <<= 1; + + /* j <-- Wrap(Integerify(X), i) */ + j = integerify(X, r) & (n - 1); + j += i - n; + + /* X <-- X \xor V_j */ + blkxor(X, &V[j * s], s); + } + + /* 4: X <-- H(X) */ + blockmix(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * s], Y, s); + + if (rw) { + /* j <-- Wrap(Integerify(X), i) */ + j = integerify(Y, r) & (n - 1); + j += (i + 1) - n; + + /* X <-- X \xor V_j */ + blkxor(Y, &V[j * s], s); + } + + /* 4: X <-- H(X) */ + blockmix(Y, X, Z, r); + } + } + + /* B' <-- X */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&X[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 8]; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * smix2(B, r, N, Nloop, flags, V, NROM, shared, XY, S): + * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The value Nloop must be even. + */ +static void +smix2(uint64_t * B, size_t r, uint64_t N, uint64_t Nloop, + yescrypt_flags_t flags, + uint64_t * V, uint64_t NROM, const yescrypt_shared_t * shared, + uint64_t * XY, uint64_t * S) +{ + void (*blockmix)(const uint64_t *, uint64_t *, uint64_t *, size_t) = + (S ? blockmix_pwxform : blockmix_salsa8); + const uint64_t * VROM = shared->shared1.aligned; + uint32_t VROM_mask = shared->mask1 | 1; + size_t s = 16 * r; + yescrypt_flags_t rw = flags & YESCRYPT_RW; + uint64_t * X = XY; + uint64_t * Y = &XY[s]; + uint64_t * Z = S ? S : &XY[2 * s]; + uint64_t i, j; + size_t k; + + if (Nloop == 0) + return; + + /* X <-- B' */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&B[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&X[i * 8]; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + + if (NROM) { + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < Nloop; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], X, s); + blockmix(X, Y, Z, r); + + j = integerify(Y, r); + if (((i + 1) & VROM_mask) == 1) { + /* j <-- Integerify(X) mod NROM */ + j &= NROM - 1; + + /* X <-- H(X \xor VROM_j) */ + blkxor(Y, &VROM[j * s], s); + } else { + /* 7: j <-- Integerify(X) mod N */ + j &= N - 1; + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], Y, s); + } + + blockmix(Y, X, Z, r); + } + } else { + /* 6: for i = 0 to N - 1 do */ + i = Nloop / 2; + do { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], X, s); + blockmix(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * s], s); + /* V_j <-- Xprev \xor V_j */ + if (rw) + blkcpy(&V[j * s], Y, s); + blockmix(Y, X, Z, r); + } while (--i); + } + + /* 10: B' <-- X */ + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (const salsa20_blk_t *)&X[i * 8]; + salsa20_blk_t *tmp = (salsa20_blk_t *)Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 8]; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * p2floor(x): + * Largest power of 2 not greater than argument. + */ +static uint64_t +p2floor(uint64_t x) +{ + uint64_t y; + while ((y = x & (x - 1))) + x = y; + return x; +} + +/** + * smix(B, r, N, p, t, flags, V, NROM, shared, XY, S): + * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * XY must be 256r+64 or (256r+64)*p bytes in length (the larger size is + * required with OpenMP-enabled builds). The value N must be a power of 2 + * greater than 1. + */ +static void +smix(uint64_t * B, size_t r, uint64_t N, uint32_t p, uint32_t t, + yescrypt_flags_t flags, + uint64_t * V, uint64_t NROM, const yescrypt_shared_t * shared, + uint64_t * XY, uint64_t * S) +{ + size_t s = 16 * r; + uint64_t Nchunk = N / p, Nloop_all, Nloop_rw; + uint32_t i; + + Nloop_all = Nchunk; + if (flags & YESCRYPT_RW) { + if (t <= 1) { + if (t) + Nloop_all *= 2; /* 2/3 */ + Nloop_all = (Nloop_all + 2) / 3; /* 1/3, round up */ + } else { + Nloop_all *= t - 1; + } + } else if (t) { + if (t == 1) + Nloop_all += (Nloop_all + 1) / 2; /* 1.5, round up */ + Nloop_all *= t; + } + + Nloop_rw = 0; + if (flags & __YESCRYPT_INIT_SHARED) + Nloop_rw = Nloop_all; + else if (flags & YESCRYPT_RW) + Nloop_rw = Nloop_all / p; + + Nchunk &= ~(uint64_t)1; /* round down to even */ + Nloop_all++; Nloop_all &= ~(uint64_t)1; /* round up to even */ + Nloop_rw &= ~(uint64_t)1; /* round down to even */ + +#ifdef _OPENMP +#pragma omp parallel if (p > 1) default(none) private(i) shared(B, r, N, p, flags, V, NROM, shared, XY, S, s, Nchunk, Nloop_all, Nloop_rw) + { +#pragma omp for +#endif + for (i = 0; i < p; i++) { + uint64_t Vchunk = i * Nchunk; + uint64_t * Bp = &B[i * s]; + uint64_t * Vp = &V[Vchunk * s]; +#ifdef _OPENMP + uint64_t * XYp = &XY[i * (2 * s + 8)]; +#else + uint64_t * XYp = XY; +#endif + uint64_t Np = (i < p - 1) ? Nchunk : (N - Vchunk); + uint64_t * Sp = S ? &S[i * S_SIZE_ALL] : S; + if (Sp) + smix1(Bp, 1, S_SIZE_ALL / 16, + flags & ~YESCRYPT_PWXFORM, + Sp, NROM, shared, XYp, NULL); + if (!(flags & __YESCRYPT_INIT_SHARED_2)) + smix1(Bp, r, Np, flags, Vp, NROM, shared, XYp, Sp); + smix2(Bp, r, p2floor(Np), Nloop_rw, flags, Vp, + NROM, shared, XYp, Sp); + } + + if (Nloop_all > Nloop_rw) { +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < p; i++) { + uint64_t * Bp = &B[i * s]; +#ifdef _OPENMP + uint64_t * XYp = &XY[i * (2 * s + 8)]; +#else + uint64_t * XYp = XY; +#endif + uint64_t * Sp = S ? &S[i * S_SIZE_ALL] : S; + smix2(Bp, r, N, Nloop_all - Nloop_rw, + flags & ~YESCRYPT_RW, V, NROM, shared, XYp, Sp); + } + } +#ifdef _OPENMP + } +#endif +} + +/** + * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, + * N, r, p, t, flags, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen), or a revision of scrypt as requested by flags and shared, and + * write the result into buf. The parameters r, p, and buflen must satisfy + * r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N must be a power + * of 2 greater than 1. + * + * t controls computation time while not affecting peak memory usage. shared + * and flags may request special modes as described in yescrypt.h. local is + * the thread-local data structure, allowing to preserve and reuse a memory + * allocation across calls, thereby reducing its overhead. + * + * Return 0 on success; or -1 on error. + */ +int +yescrypt_kdf(const yescrypt_shared_t * shared, yescrypt_local_t * local, + const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, uint32_t t, yescrypt_flags_t flags, + uint8_t * buf, size_t buflen) +{ + yescrypt_region_t tmp; + uint64_t NROM; + size_t B_size, V_size, XY_size, need; + uint64_t * B, * V, * XY, * S; + uint64_t sha256[4]; + + /* + * YESCRYPT_PARALLEL_SMIX is a no-op at p = 1 for its intended purpose, + * so don't let it have side-effects. Without this adjustment, it'd + * enable the SHA-256 password pre-hashing and output post-hashing, + * because any deviation from classic scrypt implies those. + */ + if (p == 1) + flags &= ~YESCRYPT_PARALLEL_SMIX; + + /* Sanity-check parameters */ + if (flags & ~YESCRYPT_KNOWN_FLAGS) { + errno = EINVAL; + return -1; + } +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N <= 1) || (r < 1) || (p < 1)) { + errno = EINVAL; + return -1; + } + if ((flags & YESCRYPT_PARALLEL_SMIX) && (N / p <= 1)) { + errno = EINVAL; + return -1; + } +#if S_MIN_R > 1 + if ((flags & YESCRYPT_PWXFORM) && (r < S_MIN_R)) { + errno = EINVAL; + return -1; + } +#endif + if ((p > SIZE_MAX / ((size_t)256 * r + 64)) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + if (N > UINT64_MAX / ((uint64_t)t + 1)) { + errno = EFBIG; + return -1; + } +#ifdef _OPENMP + if (!(flags & YESCRYPT_PARALLEL_SMIX) && + (N > SIZE_MAX / 128 / (r * p))) { + errno = ENOMEM; + return -1; + } +#endif + if ((flags & YESCRYPT_PWXFORM) && +#ifndef _OPENMP + (flags & YESCRYPT_PARALLEL_SMIX) && +#endif + p > SIZE_MAX / (S_SIZE_ALL * sizeof(*S))) { + errno = ENOMEM; + return -1; + } + + NROM = 0; + if (shared->shared1.aligned) { + NROM = shared->shared1.aligned_size / ((size_t)128 * r); + if (((NROM & (NROM - 1)) != 0) || (NROM <= 1) || + !(flags & YESCRYPT_RW)) { + errno = EINVAL; + return -1; + } + } + + /* Allocate memory */ + V = NULL; + V_size = (size_t)128 * r * N; +#ifdef _OPENMP + if (!(flags & YESCRYPT_PARALLEL_SMIX)) + V_size *= p; +#endif + need = V_size; + if (flags & __YESCRYPT_INIT_SHARED) { + if (local->aligned_size < need) { + if (local->base || local->aligned || + local->base_size || local->aligned_size) { + errno = EINVAL; + return -1; + } + if (!alloc_region(local, need)) + return -1; + } + V = (uint64_t *)local->aligned; + need = 0; + } + B_size = (size_t)128 * r * p; + need += B_size; + if (need < B_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t)256 * r + 64; +#ifdef _OPENMP + XY_size *= p; +#endif + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (flags & YESCRYPT_PWXFORM) { + size_t S_size = S_SIZE_ALL * sizeof(*S); +#ifdef _OPENMP + S_size *= p; +#else + if (flags & YESCRYPT_PARALLEL_SMIX) + S_size *= p; +#endif + need += S_size; + if (need < S_size) { + errno = ENOMEM; + return -1; + } + } + if (flags & __YESCRYPT_INIT_SHARED) { + if (!alloc_region(&tmp, need)) + return -1; + B = (uint64_t *)tmp.aligned; + XY = (uint64_t *)((uint8_t *)B + B_size); + } else { + init_region(&tmp); + if (local->aligned_size < need) { + if (free_region(local)) + return -1; + if (!alloc_region(local, need)) + return -1; + } + B = (uint64_t *)local->aligned; + V = (uint64_t *)((uint8_t *)B + B_size); + XY = (uint64_t *)((uint8_t *)V + V_size); + } + S = NULL; + if (flags & YESCRYPT_PWXFORM) + S = (uint64_t *)((uint8_t *)XY + XY_size); + + if (t || flags) { + SHA256_CTX_Y ctx; + SHA256_Init_Y(&ctx); + SHA256_Update_Y(&ctx, passwd, passwdlen); + SHA256_Final_Y((uint8_t *)sha256, &ctx); + passwd = (uint8_t *)sha256; + passwdlen = sizeof(sha256); + } + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256_Y(passwd, passwdlen, salt, saltlen, 1, + (uint8_t *)B, B_size); + + if (t || flags) + blkcpy(sha256, B, sizeof(sha256) / sizeof(sha256[0])); + + if (p == 1 || (flags & YESCRYPT_PARALLEL_SMIX)) { + smix(B, r, N, p, t, flags, V, NROM, shared, XY, S); + } else { + uint32_t i; + + /* 2: for i = 0 to p - 1 do */ +#ifdef _OPENMP +#pragma omp parallel for default(none) private(i) shared(B, r, N, p, t, flags, V, NROM, shared, XY, S) +#endif + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ +#ifdef _OPENMP + smix(&B[(size_t)16 * r * i], r, N, 1, t, flags, + &V[(size_t)16 * r * i * N], + NROM, shared, + &XY[((size_t)32 * r + 8) * i], + S ? &S[S_SIZE_ALL * i] : S); +#else + smix(&B[(size_t)16 * r * i], r, N, 1, t, flags, V, + NROM, shared, XY, S); +#endif + } + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256_Y(passwd, passwdlen, (uint8_t *)B, B_size, 1, buf, buflen); + + /* + * Except when computing classic scrypt, allow all computation so far + * to be performed on the client. The final steps below match those of + * SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so + * far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of + * SCRAM's use of SHA-1) would be usable with yescrypt hashes. + */ + if ((t || flags) && buflen == sizeof(sha256)) { + /* Compute ClientKey */ + { + HMAC_SHA256_CTX_Y ctx; + HMAC_SHA256_Init_Y(&ctx, buf, buflen); + if (r == 32) { // yescryptR32 + HMAC_SHA256_Update_Y(&ctx, "WaviBanana", 10); + } else + if (r == 16) { // yescryptR16 + HMAC_SHA256_Update_Y(&ctx, "Client Key", 10); + } else + if (r == 8) { // yescryptR8 + HMAC_SHA256_Update_Y(&ctx, "Client Key", 10); + } + else { // yescrypt + HMAC_SHA256_Update_Y(&ctx, salt, saltlen); + } + HMAC_SHA256_Final_Y((uint8_t *)sha256, &ctx); + } + /* Compute StoredKey */ + { + SHA256_CTX_Y ctx; + SHA256_Init_Y(&ctx); + SHA256_Update_Y(&ctx, (uint8_t *)sha256, sizeof(sha256)); + SHA256_Final_Y(buf, &ctx); + } + } + + if (free_region(&tmp)) + return -1; + + /* Success! */ + return 0; +} diff --git a/src/Native/libmultihash/yescrypt/yescrypt-platform.c b/src/Native/libmultihash/yescrypt/yescrypt-platform.c new file mode 100644 index 000000000..93b694387 --- /dev/null +++ b/src/Native/libmultihash/yescrypt/yescrypt-platform.c @@ -0,0 +1,187 @@ +/*- + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include "yescrypt.h" +#define HUGEPAGE_THRESHOLD (12 * 1024 * 1024) + +#ifdef __x86_64__ +#define HUGEPAGE_SIZE (2 * 1024 * 1024) +#else +#undef HUGEPAGE_SIZE +#endif + +static void * +alloc_region(yescrypt_region_t * region, size_t size) +{ + size_t base_size = size; + uint8_t * base, * aligned; +#ifdef MAP_ANON + int flags = +#ifdef MAP_NOCORE + MAP_NOCORE | +#endif + MAP_ANON | MAP_PRIVATE; +#if defined(MAP_HUGETLB) && defined(HUGEPAGE_SIZE) + size_t new_size = size; + const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1; + if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) { + flags |= MAP_HUGETLB; +/* + * Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of + * huge page size, so let's round up to huge page size here. + */ + new_size = size + hugepage_mask; + new_size &= ~hugepage_mask; + } + base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, flags, -1, 0); + if (base != MAP_FAILED) { + base_size = new_size; + } else + if (flags & MAP_HUGETLB) { + flags &= ~MAP_HUGETLB; + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + } + +#else + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); +#endif + if (base == MAP_FAILED) + base = NULL; + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **)&base, 64, size)) != 0) + base = NULL; + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) { + errno = ENOMEM; + } else if ((base = malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t)aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->base_size = base ? base_size : 0; + region->aligned_size = base ? size : 0; + return aligned; +} + +static inline void +init_region(yescrypt_region_t * region) +{ + region->base = region->aligned = NULL; + region->base_size = region->aligned_size = 0; +} + +static int +free_region(yescrypt_region_t * region) +{ + if (region->base) { +#ifdef MAP_ANON + if (munmap(region->base, region->base_size)) + return -1; +#else + free(region->base); +#endif + } + init_region(region); + return 0; +} + +int yescrypt_init_shared(yescrypt_shared_t * shared, + const uint8_t * param, size_t paramlen, + uint64_t N, uint32_t r, uint32_t p, + yescrypt_init_shared_flags_t flags, uint32_t mask, + uint8_t * buf, size_t buflen) +{ + yescrypt_shared1_t * shared1 = &shared->shared1; + yescrypt_shared_t dummy, half1, half2; + uint8_t salt[32]; + + if (flags & YESCRYPT_SHARED_PREALLOCATED) { + if (!shared1->aligned || !shared1->aligned_size) + return -1; + } else { + init_region(shared1); + } + shared->mask1 = 1; + if (!param && !paramlen && !N && !r && !p && !buf && !buflen) + return 0; + + init_region(&dummy.shared1); + dummy.mask1 = 1; + if (yescrypt_kdf(&dummy, shared1, + param, paramlen, NULL, 0, N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_1, + salt, sizeof(salt))) + goto out; + + half1 = half2 = *shared; + half1.shared1.aligned_size /= 2; + half2.shared1.aligned += half1.shared1.aligned_size; + half2.shared1.aligned_size = half1.shared1.aligned_size; + N /= 2; + + if (p > 1 && yescrypt_kdf(&half1, &half2.shared1, + param, paramlen, salt, sizeof(salt), N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_2, + salt, sizeof(salt))) + goto out; + + if (yescrypt_kdf(&half2, &half1.shared1, + param, paramlen, salt, sizeof(salt), N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_1, + salt, sizeof(salt))) + goto out; + + if (yescrypt_kdf(&half1, &half2.shared1, + param, paramlen, salt, sizeof(salt), N, r, p, 0, + YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | __YESCRYPT_INIT_SHARED_1, + buf, buflen)) + goto out; + + shared->mask1 = mask; + + return 0; + +out: + if (!(flags & YESCRYPT_SHARED_PREALLOCATED)) + free_region(shared1); + return -1; +} + +int yescrypt_free_shared(yescrypt_shared_t * shared) +{ + return free_region(&shared->shared1); +} + +int yescrypt_init_local(yescrypt_local_t * local) +{ + init_region(local); + return 0; +} + +int yescrypt_free_local(yescrypt_local_t * local) +{ + return free_region(local); +} diff --git a/src/Native/libmultihash/yescrypt/yescrypt.c b/src/Native/libmultihash/yescrypt/yescrypt.c new file mode 100644 index 000000000..42aecf64d --- /dev/null +++ b/src/Native/libmultihash/yescrypt/yescrypt.c @@ -0,0 +1,371 @@ +/*- + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "yescrypt.h" + +#define BYTES2CHARS(bytes) \ + ((((bytes) * 8) + 5) / 6) + +#define HASH_SIZE 32 /* bytes */ +#define HASH_LEN BYTES2CHARS(HASH_SIZE) /* base-64 chars */ +#define YESCRYPT_FLAGS (YESCRYPT_RW | YESCRYPT_PWXFORM) + +static const char * const itoa64 = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static uint8_t* encode64_uint32(uint8_t* dst, size_t dstlen, uint32_t src, uint32_t srcbits) +{ + uint32_t bit; + + for (bit = 0; bit < srcbits; bit += 6) { + if (dstlen < 1) + return NULL; + *dst++ = itoa64[src & 0x3f]; + dstlen--; + src >>= 6; + } + + return dst; +} + +static uint8_t* encode64(uint8_t* dst, size_t dstlen, const uint8_t* src, size_t srclen) +{ + size_t i; + + for (i = 0; i < srclen; ) { + uint8_t * dnext; + uint32_t value = 0, bits = 0; + do { + value |= (uint32_t)src[i++] << bits; + bits += 8; + } while (bits < 24 && i < srclen); + dnext = encode64_uint32(dst, dstlen, value, bits); + if (!dnext) + return NULL; + dstlen -= dnext - dst; + dst = dnext; + } + + return dst; +} + +static int decode64_one(uint32_t* dst, uint8_t src) +{ + const char * ptr = strchr(itoa64, src); + if (ptr) { + *dst = ptr - itoa64; + return 0; + } + *dst = 0; + return -1; +} + +static const uint8_t* decode64_uint32(uint32_t* dst, uint32_t dstbits, const uint8_t* src) +{ + uint32_t bit; + uint32_t value; + + value = 0; + for (bit = 0; bit < dstbits; bit += 6) { + uint32_t one; + if (decode64_one(&one, *src)) { + *dst = 0; + return NULL; + } + src++; + value |= one << bit; + } + + *dst = value; + return src; +} + +uint8_t* yescrypt_r(const yescrypt_shared_t* shared, yescrypt_local_t* local, + const uint8_t* passwd, size_t passwdlen, const uint8_t* setting, uint8_t* buf, size_t buflen) +{ + uint8_t hash[HASH_SIZE]; + const uint8_t * src, * salt; + uint8_t * dst; + size_t prefixlen, saltlen, need; + uint8_t version; + uint64_t N; + uint32_t r, p; + yescrypt_flags_t flags = YESCRYPT_WORM; + + printf("pass1 ..."); + fflush(stdout); + + if (setting[0] != '$' || setting[1] != '7') { + printf("died$7 ..."); + fflush(stdout); + return NULL; + } + + printf("died80 ..."); + fflush(stdout); + + src = setting + 2; + + printf("hello '%p'\n", (char *)src); + fflush(stdout); + + switch ((version = *src)) { + case '$': + printf("died2 ..."); + fflush(stdout); + break; + case 'X': + src++; + flags = YESCRYPT_RW; + printf("died3 ..."); + fflush(stdout); + break; + default: + printf("died4 ..."); + fflush(stdout); + return NULL; + } + + printf("pass2 ..."); + fflush(stdout); + + if (*src != '$') { + uint32_t decoded_flags; + if (decode64_one(&decoded_flags, *src)) { + printf("died5 ..."); + fflush(stdout); + return NULL; + } + flags = decoded_flags; + if (*++src != '$') { + printf("died6 ..."); + fflush(stdout); + return NULL; + } + } + + src++; + + { + uint32_t N_log2; + if (decode64_one(&N_log2, *src)) { + printf("died7 ..."); + return NULL; + } + src++; + N = (uint64_t)1 << N_log2; + } + + src = decode64_uint32(&r, 30, src); + if (!src) { + printf("died6 ..."); + return NULL; + } + + src = decode64_uint32(&p, 30, src); + if (!src) { + printf("died7 ..."); + return NULL; + } + + prefixlen = src - setting; + + salt = src; + src = (uint8_t *)strrchr((char *)salt, '$'); + if (src) + saltlen = src - salt; + else + saltlen = strlen((char *)salt); + + need = prefixlen + saltlen + 1 + HASH_LEN + 1; + if (need > buflen || need < saltlen) { + printf("'%d %d %d'", (int) need, (int) buflen, (int) saltlen); + printf("died8killbuf ..."); + fflush(stdout); + return NULL; + } + + if (yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, N, r, p, 0, flags, hash, sizeof(hash))) { + printf("died10 ..."); + fflush(stdout); + return NULL; + } + + dst = buf; + memcpy(dst, setting, prefixlen + saltlen); + dst += prefixlen + saltlen; + *dst++ = '$'; + + dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); + /* Could zeroize hash[] here, but yescrypt_kdf() doesn't zeroize its + * memory allocations yet anyway. */ + if (!dst || dst >= buf + buflen) { /* Can't happen */ + printf("died11 ..."); + return NULL; + } + + *dst = 0; /* NUL termination */ + + printf("died12 ..."); + fflush(stdout); + + return buf; +} + +uint8_t* yescrypt(const uint8_t* passwd, const uint8_t* setting) +{ + static uint8_t buf[4 + 1 + 5 + 5 + BYTES2CHARS(32) + 1 + HASH_LEN + 1]; + yescrypt_shared_t shared; + yescrypt_local_t local; + uint8_t * retval; + + if (yescrypt_init_shared(&shared, NULL, 0, + 0, 0, 0, YESCRYPT_SHARED_DEFAULTS, 0, NULL, 0)) + return NULL; + if (yescrypt_init_local(&local)) { + yescrypt_free_shared(&shared); + return NULL; + } + retval = yescrypt_r(&shared, &local, + passwd, 80, setting, buf, sizeof(buf)); + //printf("hashse='%s'\n", (char *)retval); + if (yescrypt_free_local(&local)) { + yescrypt_free_shared(&shared); + return NULL; + } + if (yescrypt_free_shared(&shared)) + return NULL; + return retval; +} + +uint8_t* yescrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, yescrypt_flags_t flags, + const uint8_t* src, size_t srclen, uint8_t* buf, size_t buflen) +{ + uint8_t * dst; + size_t prefixlen = 3 + 1 + 5 + 5; + size_t saltlen = BYTES2CHARS(srclen); + size_t need; + + if (p == 1) + flags &= ~YESCRYPT_PARALLEL_SMIX; + + if (flags) { + if (flags & ~0x3f) + return NULL; + + prefixlen++; + if (flags != YESCRYPT_RW) + prefixlen++; + } + + need = prefixlen + saltlen + 1; + if (need > buflen || need < saltlen || saltlen < srclen) + return NULL; + + if (N_log2 > 63 || ((uint64_t)r * (uint64_t)p >= (1U << 30))) + return NULL; + + dst = buf; + *dst++ = '$'; + *dst++ = '7'; + if (flags) { + *dst++ = 'X'; /* eXperimental, subject to change */ + if (flags != YESCRYPT_RW) + *dst++ = itoa64[flags]; + } + *dst++ = '$'; + + *dst++ = itoa64[N_log2]; + + dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); + if (!dst) /* Can't happen */ + return NULL; + + dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); + if (!dst) /* Can't happen */ + return NULL; + + dst = encode64(dst, buflen - (dst - buf), src, srclen); + if (!dst || dst >= buf + buflen) /* Can't happen */ + return NULL; + + *dst = 0; /* NUL termination */ + + return buf; +} + +uint8_t* yescrypt_gensalt(uint32_t N_log2, uint32_t r, uint32_t p, yescrypt_flags_t flags, + const uint8_t * src, size_t srclen) +{ + static uint8_t buf[4 + 1 + 5 + 5 + BYTES2CHARS(32) + 1]; + return yescrypt_gensalt_r(N_log2, r, p, flags, src, srclen, + buf, sizeof(buf)); +} + +static int yescrypt_bsty(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + yescrypt_shared_t shared; + yescrypt_local_t local; + int retval; + + if (yescrypt_init_shared(&shared, NULL, 0, + 0, 0, 0, YESCRYPT_SHARED_DEFAULTS, 0, NULL, 0)) + return -1; + if (yescrypt_init_local(&local)) { + yescrypt_free_shared(&shared); + return -1; + } + + retval = yescrypt_kdf(&shared, &local, + passwd, passwdlen, salt, saltlen, N, r, p, 0, YESCRYPT_FLAGS, + buf, buflen); + + yescrypt_free_local(&local); + yescrypt_free_shared(&shared); + + return retval; +} + +/* main hash 80 bytes input */ +void yescrypt_hash(const char *input, char *output, uint32_t len) +{ + yescrypt_bsty((uint8_t*)input, len, (uint8_t*)input, len, 2048, 8, 1, (uint8_t*)output, 32); +} + +void yescryptR8_hash(const char *input, char *output, uint32_t len) +{ + yescrypt_bsty((uint8_t*)input, len, (uint8_t*)input, len, 2048, 8, 1, (uint8_t*)output, 32); +} + +void yescryptR16_hash(const char *input, char *output, uint32_t len) +{ + yescrypt_bsty((uint8_t*)input, len, (uint8_t*)input, len, 4096, 16, 1, (uint8_t*)output, 32); +} + +void yescryptR32_hash(const char *input, char *output, uint32_t len) +{ + yescrypt_bsty((uint8_t*)input, len, (uint8_t*)input, len, 4096, 32, 1, (uint8_t*)output, 32); +} diff --git a/src/Native/libmultihash/yescrypt/yescrypt.h b/src/Native/libmultihash/yescrypt/yescrypt.h new file mode 100644 index 000000000..7fb880d6c --- /dev/null +++ b/src/Native/libmultihash/yescrypt/yescrypt.h @@ -0,0 +1,375 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013,2014 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#ifndef YESCRYPT_H +#define YESCRYPT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include /* for size_t */ + +void yescrypt_hash(const char* input, char* output, uint32_t len); +void yescryptR8_hash(const char* input, char* output, uint32_t len); +void yescryptR16_hash(const char* input, char* output, uint32_t len); +void yescryptR32_hash(const char* input, char* output, uint32_t len); + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as buf is local to the thread. + */ +extern int crypto_scrypt(const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +/** + * Internal type used by the memory allocator. Please do not use it directly. + * Use yescrypt_shared_t and yescrypt_local_t as appropriate instead, since + * they might differ from each other in a future version. + */ +typedef struct { + void * base, * aligned; + size_t base_size, aligned_size; +} yescrypt_region_t; + +/** + * Types for shared (ROM) and thread-local (RAM) data structures. + */ +typedef yescrypt_region_t yescrypt_shared1_t; +typedef struct { + yescrypt_shared1_t shared1; + uint32_t mask1; +} yescrypt_shared_t; +typedef yescrypt_region_t yescrypt_local_t; + +/** + * Possible values for yescrypt_init_shared()'s flags argument. + */ +typedef enum { + YESCRYPT_SHARED_DEFAULTS = 0, + YESCRYPT_SHARED_PREALLOCATED = 0x100 +} yescrypt_init_shared_flags_t; + +/** + * Possible values for the flags argument of yescrypt_kdf(), + * yescrypt_gensalt_r(), yescrypt_gensalt(). These may be OR'ed together, + * except that YESCRYPT_WORM and YESCRYPT_RW are mutually exclusive. + * Please refer to the description of yescrypt_kdf() below for the meaning of + * these flags. + */ +typedef enum { +/* public */ + YESCRYPT_WORM = 0, + YESCRYPT_RW = 1, + YESCRYPT_PARALLEL_SMIX = 2, + YESCRYPT_PWXFORM = 4, +/* private */ + __YESCRYPT_INIT_SHARED_1 = 0x10000, + __YESCRYPT_INIT_SHARED_2 = 0x20000, + __YESCRYPT_INIT_SHARED = 0x30000 +} yescrypt_flags_t; + +#define YESCRYPT_KNOWN_FLAGS \ + (YESCRYPT_RW | YESCRYPT_PARALLEL_SMIX | YESCRYPT_PWXFORM | \ + __YESCRYPT_INIT_SHARED) + +/** + * yescrypt_init_shared(shared, param, paramlen, N, r, p, flags, mask, + * buf, buflen): + * Optionally allocate memory for and initialize the shared (ROM) data + * structure. The parameters N, r, and p must satisfy the same conditions as + * with crypto_scrypt(). param and paramlen specify a local parameter with + * which the ROM is seeded. If buf is not NULL, then it is used to return + * buflen bytes of message digest for the initialized ROM (the caller may use + * this to verify that the ROM has been computed in the same way that it was on + * a previous run). + * + * Return 0 on success; or -1 on error. + * + * If bit YESCRYPT_SHARED_PREALLOCATED in flags is set, then memory for the + * ROM is assumed to have been preallocated by the caller, with + * shared->shared1.aligned being the start address of the ROM and + * shared->shared1.aligned_size being its size (which must be consistent with + * N, r, and p). This may be used e.g. when the ROM is to be placed in a SysV + * shared memory segment allocated by the caller. + * + * mask controls the frequency of ROM accesses by yescrypt_kdf(). Normally it + * should be set to 1, to interleave RAM and ROM accesses, which works well + * when both regions reside in the machine's RAM anyway. Other values may be + * used e.g. when the ROM is memory-mapped from a disk file. Recommended mask + * values are powers of 2 minus 1 or minus 2. Here's the effect of some mask + * values: + * mask value ROM accesses in SMix 1st loop ROM accesses in SMix 2nd loop + * 0 0 1/2 + * 1 1/2 1/2 + * 2 0 1/4 + * 3 1/4 1/4 + * 6 0 1/8 + * 7 1/8 1/8 + * 14 0 1/16 + * 15 1/16 1/16 + * 1022 0 1/1024 + * 1023 1/1024 1/1024 + * + * Actual computation of the ROM contents may be avoided, if you don't intend + * to use a ROM but need a dummy shared structure, by calling this function + * with NULL, 0, 0, 0, 0, YESCRYPT_SHARED_DEFAULTS, 0, NULL, 0 for the + * arguments starting with param and on. + * + * MT-safe as long as shared is local to the thread. + */ +extern int yescrypt_init_shared(yescrypt_shared_t * __shared, + const uint8_t * __param, size_t __paramlen, + uint64_t __N, uint32_t __r, uint32_t __p, + yescrypt_init_shared_flags_t __flags, uint32_t __mask, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt_free_shared(shared): + * Free memory that had been allocated with yescrypt_init_shared(). + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as shared is local to the thread. + */ +extern int yescrypt_free_shared(yescrypt_shared_t * __shared); + +/** + * yescrypt_init_local(local): + * Initialize the thread-local (RAM) data structure. Actual memory allocation + * is currently fully postponed until a call to yescrypt_kdf() or yescrypt_r(). + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yescrypt_init_local(yescrypt_local_t * __local); + +/** + * yescrypt_free_local(local): + * Free memory that may have been allocated for an initialized thread-local + * (RAM) data structure. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yescrypt_free_local(yescrypt_local_t * __local); + +/** + * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, + * N, r, p, t, flags, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen), or a revision of scrypt as requested by flags and shared, and + * write the result into buf. The parameters N, r, p, and buflen must satisfy + * the same conditions as with crypto_scrypt(). t controls computation time + * while not affecting peak memory usage. shared and flags may request + * special modes as described below. local is the thread-local data + * structure, allowing to preserve and reuse a memory allocation across calls, + * thereby reducing its overhead. + * + * Return 0 on success; or -1 on error. + * + * t controls computation time. t = 0 is optimal in terms of achieving the + * highest area-time for ASIC attackers. Thus, higher computation time, if + * affordable, is best achieved by increasing N rather than by increasing t. + * However, if the higher memory usage (which goes along with higher N) is not + * affordable, or if fine-tuning of the time is needed (recall that N must be a + * power of 2), then t = 1 or above may be used to increase time while staying + * at the same peak memory usage. t = 1 increases the time by 25% and + * decreases the normalized area-time to 96% of optimal. (Of course, in + * absolute terms the area-time increases with higher t. It's just that it + * would increase slightly more with higher N*r rather than with higher t.) + * t = 2 increases the time by another 20% and decreases the normalized + * area-time to 89% of optimal. Thus, these two values are reasonable to use + * for fine-tuning. Values of t higher than 2 result in further increase in + * time while reducing the efficiency much further (e.g., down to around 50% of + * optimal for t = 5, which runs 3 to 4 times slower than t = 0, with exact + * numbers varying by the flags settings). + * + * Classic scrypt is available by setting t = 0 and flags to YESCRYPT_WORM and + * passing a dummy shared structure (see the description of + * yescrypt_init_shared() above for how to produce one). In this mode, the + * thread-local memory region (RAM) is first sequentially written to and then + * randomly read from. This algorithm is friendly towards time-memory + * tradeoffs (TMTO), available both to defenders (albeit not in this + * implementation) and to attackers. + * + * Setting YESCRYPT_RW adds extra random reads and writes to the thread-local + * memory region (RAM), which makes TMTO a lot less efficient. This may be + * used to slow down the kinds of attackers who would otherwise benefit from + * classic scrypt's efficient TMTO. Since classic scrypt's TMTO allows not + * only for the tradeoff, but also for a decrease of attacker's area-time (by + * up to a constant factor), setting YESCRYPT_RW substantially increases the + * cost of attacks in area-time terms as well. Yet another benefit of it is + * that optimal area-time is reached at an earlier time than with classic + * scrypt, and t = 0 actually corresponds to this earlier completion time, + * resulting in quicker hash computations (and thus in higher request rate + * capacity). Due to these properties, YESCRYPT_RW should almost always be + * set, except when compatibility with classic scrypt or TMTO-friendliness are + * desired. + * + * YESCRYPT_PARALLEL_SMIX moves parallelism that is present with p > 1 to a + * lower level as compared to where it is in classic scrypt. This reduces + * flexibility for efficient computation (for both attackers and defenders) by + * requiring that, short of resorting to TMTO, the full amount of memory be + * allocated as needed for the specified p, regardless of whether that + * parallelism is actually being fully made use of or not. (For comparison, a + * single instance of classic scrypt may be computed in less memory without any + * CPU time overhead, but in more real time, by not making full use of the + * parallelism.) This may be desirable when the defender has enough memory + * with sufficiently low latency and high bandwidth for efficient full parallel + * execution, yet the required memory size is high enough that some likely + * attackers might end up being forced to choose between using higher latency + * memory than they could use otherwise (waiting for data longer) or using TMTO + * (waiting for data more times per one hash computation). The area-time cost + * for other kinds of attackers (who would use the same memory type and TMTO + * factor or no TMTO either way) remains roughly the same, given the same + * running time for the defender. In the TMTO-friendly YESCRYPT_WORM mode, as + * long as the defender has enough memory that is just as fast as the smaller + * per-thread regions would be, doesn't expect to ever need greater + * flexibility (except possibly via TMTO), and doesn't need backwards + * compatibility with classic scrypt, there are no other serious drawbacks to + * this setting. In the YESCRYPT_RW mode, which is meant to discourage TMTO, + * this new approach to parallelization makes TMTO less inefficient. (This is + * an unfortunate side-effect of avoiding some random writes, as we have to in + * order to allow for parallel threads to access a common memory region without + * synchronization overhead.) Thus, in this mode this setting poses an extra + * tradeoff of its own (higher area-time cost for a subset of attackers vs. + * better TMTO resistance). Setting YESCRYPT_PARALLEL_SMIX also changes the + * way the running time is to be controlled from N*r*p (for classic scrypt) to + * N*r (in this modification). All of this applies only when p > 1. For + * p = 1, this setting is a no-op. + * + * Passing a real shared structure, with ROM contents previously computed by + * yescrypt_init_shared(), enables the use of ROM and requires YESCRYPT_RW for + * the thread-local RAM region. In order to allow for initialization of the + * ROM to be split into a separate program, the shared->shared1.aligned and + * shared->shared1.aligned_size fields may be set by the caller of + * yescrypt_kdf() manually rather than with yescrypt_init_shared(). + * + * local must be initialized with yescrypt_init_local(). + * + * MT-safe as long as local and buf are local to the thread. + */ +extern int yescrypt_kdf(const yescrypt_shared_t * __shared, + yescrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, uint32_t __t, + yescrypt_flags_t __flags, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt_r(shared, local, passwd, passwdlen, setting, buf, buflen): + * Compute and encode an scrypt or enhanced scrypt hash of passwd given the + * parameters and salt value encoded in setting. If the shared structure is + * not dummy, a ROM is used and YESCRYPT_RW is required. Otherwise, whether to + * use the YESCRYPT_WORM (classic scrypt) or YESCRYPT_RW (time-memory tradeoff + * discouraging modification) is determined by the setting string. shared and + * local must be initialized as described above for yescrypt_kdf(). buf must + * be large enough (as indicated by buflen) to hold the encoded hash string. + * + * Return the encoded hash string on success; or NULL on error. + * + * MT-safe as long as local and buf are local to the thread. + */ +extern uint8_t * yescrypt_r(const yescrypt_shared_t * __shared, + yescrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __setting, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt(passwd, setting): + * Compute and encode an scrypt or enhanced scrypt hash of passwd given the + * parameters and salt value encoded in setting. Whether to use the + * YESCRYPT_WORM (classic scrypt) or YESCRYPT_RW (time-memory tradeoff + * discouraging modification) is determined by the setting string. + * + * Return the encoded hash string on success; or NULL on error. + * + * This is a crypt(3)-like interface, which is simpler to use than + * yescrypt_r(), but it is not MT-safe, it does not allow for the use of a ROM, + * and it is slower than yescrypt_r() for repeated calls because it allocates + * and frees memory on each call. + * + * MT-unsafe. + */ +extern uint8_t * yescrypt(const uint8_t * __passwd, const uint8_t * __setting); + +/** + * yescrypt_gensalt_r(N_log2, r, p, flags, src, srclen, buf, buflen): + * Generate a setting string for use with yescrypt_r() and yescrypt() by + * encoding into it the parameters N_log2 (which is to be set to base 2 + * logarithm of the desired value for N), r, p, flags, and a salt given by src + * (of srclen bytes). buf must be large enough (as indicated by buflen) to + * hold the setting string. + * + * Return the setting string on success; or NULL on error. + * + * MT-safe as long as buf is local to the thread. + */ +extern uint8_t * yescrypt_gensalt_r( + uint32_t __N_log2, uint32_t __r, uint32_t __p, + yescrypt_flags_t __flags, + const uint8_t * __src, size_t __srclen, + uint8_t * __buf, size_t __buflen); + +/** + * yescrypt_gensalt(N_log2, r, p, flags, src, srclen): + * Generate a setting string for use with yescrypt_r() and yescrypt(). This + * function is the same as yescrypt_gensalt_r() except that it uses a static + * buffer and thus is not MT-safe. + * + * Return the setting string on success; or NULL on error. + * + * MT-unsafe. + */ +extern uint8_t * yescrypt_gensalt( + uint32_t __N_log2, uint32_t __r, uint32_t __p, + yescrypt_flags_t __flags, + const uint8_t * __src, size_t __srclen); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Native/libmultihash/yespower/crypto/blake2b-yp.c b/src/Native/libmultihash/yespower/crypto/blake2b-yp.c new file mode 100644 index 000000000..3134b9e02 --- /dev/null +++ b/src/Native/libmultihash/yespower/crypto/blake2b-yp.c @@ -0,0 +1,322 @@ +/* + * Copyright 2009 Colin Percival, 2014 savale + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include + +#include "sph_types.h" +#include "../sysendian.h" +#include "blake2b-yp.h" + +// Cyclic right rotation. +#ifndef ROTR64 +#define ROTR64(x, y) (((x) >> (y)) ^ ((x) << (64 - (y)))) +#endif + +// Little-endian byte access. +#define B2B_GET64(p) \ + (((uint64_t) ((uint8_t *) (p))[0]) ^ \ + (((uint64_t) ((uint8_t *) (p))[1]) << 8) ^ \ + (((uint64_t) ((uint8_t *) (p))[2]) << 16) ^ \ + (((uint64_t) ((uint8_t *) (p))[3]) << 24) ^ \ + (((uint64_t) ((uint8_t *) (p))[4]) << 32) ^ \ + (((uint64_t) ((uint8_t *) (p))[5]) << 40) ^ \ + (((uint64_t) ((uint8_t *) (p))[6]) << 48) ^ \ + (((uint64_t) ((uint8_t *) (p))[7]) << 56)) + +// G Mixing function. +#define B2B_G(a, b, c, d, x, y) { \ + v[a] = v[a] + v[b] + x; \ + v[d] = ROTR64(v[d] ^ v[a], 32); \ + v[c] = v[c] + v[d]; \ + v[b] = ROTR64(v[b] ^ v[c], 24); \ + v[a] = v[a] + v[b] + y; \ + v[d] = ROTR64(v[d] ^ v[a], 16); \ + v[c] = v[c] + v[d]; \ + v[b] = ROTR64(v[b] ^ v[c], 63); } + +// Initialization Vector. +static const uint64_t blake2b_iv[8] = { + 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, + 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, + 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, + 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 +}; + +// Compression function. "last" flag indicates last block. +static void blake2b_compress(blake2b_yp_ctx *ctx, int last) +{ + const uint8_t sigma[12][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } + }; + int i; + uint64_t v[16], m[16]; + + // init work variables + for (i = 0; i < 8; i++) { + v[i] = ctx->h[i]; + v[i + 8] = blake2b_iv[i]; + } + + v[12] ^= ctx->t[0]; // low 64 bits of offset + v[13] ^= ctx->t[1]; // high 64 bits + + // last block flag set ? + if (last) { + v[14] = ~v[14]; + } + + // get little-endian words + for (i = 0; i < 16; i++) { + m[i] = B2B_GET64(&ctx->b[8 * i]); + } + + // twelve rounds + for (i = 0; i < 12; i++) { + B2B_G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]); + B2B_G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]); + B2B_G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]); + B2B_G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]); + B2B_G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]); + B2B_G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]); + B2B_G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]); + B2B_G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]); + } + + for(i = 0; i < 8; ++i) { + ctx->h[i] ^= v[i] ^ v[i + 8]; + } +} + +// Initialize the hashing context "ctx" with optional key "key". +// 1 <= outlen <= 64 gives the digest size in bytes. +// Secret key (also <= 64 bytes) is optional (keylen = 0). +int blake2b_yp_init(blake2b_yp_ctx *ctx, size_t outlen, + const void *key, size_t keylen) // (keylen=0: no key) +{ + size_t i; + + // illegal parameters + if (outlen == 0 || outlen > 64 || keylen > 64) { + return -1; + } + + // state, "param block" + for (i = 0; i < 8; i++) { + ctx->h[i] = blake2b_iv[i]; + } + + ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen; + + ctx->t[0] = 0; // input count low word + ctx->t[1] = 0; // input count high word + ctx->c = 0; // pointer within buffer + ctx->outlen = outlen; + + // zero input block + for (i = keylen; i < 128; i++) { + ctx->b[i] = 0; + } + + if (keylen > 0) { + blake2b_yp_update(ctx, key, keylen); + ctx->c = 128; // at the end + } + + return 0; +} + +// Add "inlen" bytes from "in" into the hash. +void blake2b_yp_update(blake2b_yp_ctx *ctx, + const void *in, size_t inlen) // data bytes +{ + size_t i; + for (i = 0; i < inlen; i++) { + if (ctx->c == 128) { // buffer full ? + ctx->t[0] += ctx->c; // add counters + if (ctx->t[0] < ctx->c) // carry overflow ? + ctx->t[1]++; // high word + blake2b_compress(ctx, 0); // compress (not last) + ctx->c = 0; // counter to zero + } + ctx->b[ctx->c++] = ((const uint8_t *) in)[i]; + } +} + +// Generate the message digest (size given in init). +// Result placed in "out". +void blake2b_yp_final(blake2b_yp_ctx *ctx, void *out) +{ + size_t i; + + ctx->t[0] += ctx->c; // mark last block offset + // carry overflow + if (ctx->t[0] < ctx->c) { + ctx->t[1]++; // high word + } + + // fill up with zeros + while (ctx->c < 128) { + ctx->b[ctx->c++] = 0; + } + + blake2b_compress(ctx, 1); // final block flag = 1 + + // little endian convert and store + for (i = 0; i < ctx->outlen; i++) { + ((uint8_t *) out)[i] = + (ctx->h[i >> 3] >> (8 * (i & 7))) & 0xFF; + } +} + +// inlen = number of bytes +void blake2b_yp_hash(void *out, const void *in, size_t inlen) { + blake2b_yp_ctx ctx; + blake2b_yp_init(&ctx, 32, NULL, 0); + blake2b_yp_update(&ctx, in, inlen); + blake2b_yp_final(&ctx, out); +} + +// // keylen = number of bytes +void hmac_blake2b_init(hmac_yp_ctx *hctx, const void *_key, size_t keylen) { + const uint8_t *key = _key; + uint8_t keyhash[32]; + uint8_t pad[64]; + uint64_t i; + + if (keylen > 64) { + blake2b_yp_hash(keyhash, key, keylen); + key = keyhash; + keylen = 32; + } + + blake2b_yp_init(&hctx->inner, 32, NULL, 0); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + + blake2b_yp_update(&hctx->inner, pad, 64); + blake2b_yp_init(&hctx->outer, 32, NULL, 0); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; ++i) { + pad[i] ^= key[i]; + } + + blake2b_yp_update(&hctx->outer, pad, 64); + memset(keyhash, 0, 32); +} + +// datalen = number of bits +void hmac_blake2b_update(hmac_yp_ctx *hctx, const void *data, size_t datalen) { + // update the inner state + blake2b_yp_update(&hctx->inner, data, datalen); +} + +void hmac_blake2b_final(hmac_yp_ctx *hctx, uint8_t *digest) { + uint8_t ihash[32]; + blake2b_yp_final(&hctx->inner, ihash); + blake2b_yp_update(&hctx->outer, ihash, 32); + blake2b_yp_final(&hctx->outer, digest); + memset(ihash, 0, 32); +} + +// // keylen = number of bytes; inlen = number of bytes +void hmac_blake2b_yp_hash(void *out, const void *key, size_t keylen, const void *in, size_t inlen) { + hmac_yp_ctx hctx; + hmac_blake2b_init(&hctx, key, keylen); + hmac_blake2b_update(&hctx, in, inlen); + hmac_blake2b_final(&hctx, out); +} + +void pbkdf2_blake2b_yp(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + hmac_yp_ctx PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Compute HMAC state after processing P and S. */ + hmac_blake2b_init(&PShctx, passwd, passwdlen); + hmac_blake2b_update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(hmac_yp_ctx)); + hmac_blake2b_update(&hctx, ivec, 4); + hmac_blake2b_final(&hctx, U); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + hmac_blake2b_init(&hctx, passwd, passwdlen); + hmac_blake2b_update(&hctx, U, 32); + hmac_blake2b_final(&hctx, U); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) { + T[k] ^= U[k]; + } + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) { + clen = 32; + } + + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + memset(&PShctx, 0, sizeof(hmac_yp_ctx)); +} diff --git a/src/Native/libmultihash/yespower/crypto/blake2b-yp.h b/src/Native/libmultihash/yespower/crypto/blake2b-yp.h new file mode 100644 index 000000000..a240bc6a6 --- /dev/null +++ b/src/Native/libmultihash/yespower/crypto/blake2b-yp.h @@ -0,0 +1,42 @@ +#pragma once +#ifndef __BLAKE2B_H__ +#define __BLAKE2B_H__ + +#include +#include + +#if defined(_MSC_VER) || defined(__x86_64__) || defined(__x86__) +#define NATIVE_LITTLE_ENDIAN +#endif + +// state context +typedef struct { + uint8_t b[128]; // input buffer + uint64_t h[8]; // chained state + uint64_t t[2]; // total number of bytes + size_t c; // pointer for b[] + size_t outlen; // digest size +} blake2b_yp_ctx; + +typedef struct { + blake2b_yp_ctx inner; + blake2b_yp_ctx outer; +} hmac_yp_ctx; + +#if defined(__cplusplus) +extern "C" { +#endif + +int blake2b_yp_init(blake2b_yp_ctx *ctx, size_t outlen, const void *key, size_t keylen); +void blake2b_yp_update(blake2b_yp_ctx *ctx, const void *in, size_t inlen); +void blake2b_yp_final(blake2b_yp_ctx *ctx, void *out); +void blake2b_yp_hash(void *out, const void *in, size_t inlen); +void hmac_blake2b_yp_hash(void *out, const void *key, size_t keylen, const void *in, size_t inlen); +void pbkdf2_blake2b_yp(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/Native/libmultihash/yespower/crypto/sph_types.h b/src/Native/libmultihash/yespower/crypto/sph_types.h new file mode 100644 index 000000000..cef79bde1 --- /dev/null +++ b/src/Native/libmultihash/yespower/crypto/sph_types.h @@ -0,0 +1,1976 @@ +/* $Id: sph_types.h 260 2011-07-21 01:02:38Z tp $ */ +/** + * Basic type definitions. + * + * This header file defines the generic integer types that will be used + * for the implementation of hash functions; it also contains helper + * functions which encode and decode multi-byte integer values, using + * either little-endian or big-endian conventions. + * + * This file contains a compile-time test on the size of a byte + * (the unsigned char C type). If bytes are not octets, + * i.e. if they do not have a size of exactly 8 bits, then compilation + * is aborted. Architectures where bytes are not octets are relatively + * rare, even in the embedded devices market. We forbid non-octet bytes + * because there is no clear convention on how octet streams are encoded + * on such systems. + * + * ==========================(LICENSE BEGIN)============================ + * + * Copyright (c) 2007-2010 Projet RNRT SAPHIR + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ===========================(LICENSE END)============================= + * + * @file sph_types.h + * @author Thomas Pornin + */ + +#ifndef SPH_TYPES_H__ +#define SPH_TYPES_H__ + +#include + +/* + * All our I/O functions are defined over octet streams. We do not know + * how to handle input data if bytes are not octets. + */ +#if CHAR_BIT != 8 +#error This code requires 8-bit bytes +#endif + +/* ============= BEGIN documentation block for Doxygen ============ */ + +#ifdef DOXYGEN_IGNORE + +/** @mainpage sphlib C code documentation + * + * @section overview Overview + * + * sphlib is a library which contains implementations of + * various cryptographic hash functions. These pages have been generated + * with doxygen and + * document the API for the C implementations. + * + * The API is described in appropriate header files, which are available + * in the "Files" section. Each hash function family has its own header, + * whose name begins with "sph_" and contains the family + * name. For instance, the API for the RIPEMD hash functions is available + * in the header file sph_ripemd.h. + * + * @section principles API structure and conventions + * + * @subsection io Input/output conventions + * + * In all generality, hash functions operate over strings of bits. + * Individual bits are rarely encountered in C programming or actual + * communication protocols; most protocols converge on the ubiquitous + * "octet" which is a group of eight bits. Data is thus expressed as a + * stream of octets. The C programming language contains the notion of a + * "byte", which is a data unit managed under the type "unsigned + * char". The C standard prescribes that a byte should hold at + * least eight bits, but possibly more. Most modern architectures, even + * in the embedded world, feature eight-bit bytes, i.e. map bytes to + * octets. + * + * Nevertheless, for some of the implemented hash functions, an extra + * API has been added, which allows the input of arbitrary sequences of + * bits: when the computation is about to be closed, 1 to 7 extra bits + * can be added. The functions for which this API is implemented include + * the SHA-2 functions and all SHA-3 candidates. + * + * sphlib defines hash function which may hash octet streams, + * i.e. streams of bits where the number of bits is a multiple of eight. + * The data input functions in the sphlib API expect data + * as anonymous pointers ("const void *") with a length + * (of type "size_t") which gives the input data chunk length + * in bytes. A byte is assumed to be an octet; the sph_types.h + * header contains a compile-time test which prevents compilation on + * architectures where this property is not met. + * + * The hash function output is also converted into bytes. All currently + * implemented hash functions have an output width which is a multiple of + * eight, and this is likely to remain true for new designs. + * + * Most hash functions internally convert input data into 32-bit of 64-bit + * words, using either little-endian or big-endian conversion. The hash + * output also often consists of such words, which are encoded into output + * bytes with a similar endianness convention. Some hash functions have + * been only loosely specified on that subject; when necessary, + * sphlib has been tested against published "reference" + * implementations in order to use the same conventions. + * + * @subsection shortname Function short name + * + * Each implemented hash function has a "short name" which is used + * internally to derive the identifiers for the functions and context + * structures which the function uses. For instance, MD5 has the short + * name "md5". Short names are listed in the next section, + * for the implemented hash functions. In subsequent sections, the + * short name will be assumed to be "XXX": replace with the + * actual hash function name to get the C identifier. + * + * Note: some functions within the same family share the same core + * elements, such as update function or context structure. Correspondingly, + * some of the defined types or functions may actually be macros which + * transparently evaluate to another type or function name. + * + * @subsection context Context structure + * + * Each implemented hash fonction has its own context structure, available + * under the type name "sph_XXX_context" for the hash function + * with short name "XXX". This structure holds all needed + * state for a running hash computation. + * + * The contents of these structures are meant to be opaque, and private + * to the implementation. However, these contents are specified in the + * header files so that application code which uses sphlib + * may access the size of those structures. + * + * The caller is responsible for allocating the context structure, + * whether by dynamic allocation (malloc() or equivalent), + * static allocation (a global permanent variable), as an automatic + * variable ("on the stack"), or by any other mean which ensures proper + * structure alignment. sphlib code performs no dynamic + * allocation by itself. + * + * The context must be initialized before use, using the + * sph_XXX_init() function. This function sets the context + * state to proper initial values for hashing. + * + * Since all state data is contained within the context structure, + * sphlib is thread-safe and reentrant: several hash + * computations may be performed in parallel, provided that they do not + * operate on the same context. Moreover, a running computation can be + * cloned by copying the context (with a simple memcpy()): + * the context and its clone are then independant and may be updated + * with new data and/or closed without interfering with each other. + * Similarly, a context structure can be moved in memory at will: + * context structures contain no pointer, in particular no pointer to + * themselves. + * + * @subsection dataio Data input + * + * Hashed data is input with the sph_XXX() fonction, which + * takes as parameters a pointer to the context, a pointer to the data + * to hash, and the number of data bytes to hash. The context is updated + * with the new data. + * + * Data can be input in one or several calls, with arbitrary input lengths. + * However, it is best, performance wise, to input data by relatively big + * chunks (say a few kilobytes), because this allows sphlib to + * optimize things and avoid internal copying. + * + * When all data has been input, the context can be closed with + * sph_XXX_close(). The hash output is computed and written + * into the provided buffer. The caller must take care to provide a + * buffer of appropriate length; e.g., when using SHA-1, the output is + * a 20-byte word, therefore the output buffer must be at least 20-byte + * long. + * + * For some hash functions, the sph_XXX_addbits_and_close() + * function can be used instead of sph_XXX_close(). This + * function can take a few extra bits to be added at + * the end of the input message. This allows hashing messages with a + * bit length which is not a multiple of 8. The extra bits are provided + * as an unsigned integer value, and a bit count. The bit count must be + * between 0 and 7, inclusive. The extra bits are provided as bits 7 to + * 0 (bits of numerical value 128, 64, 32... downto 0), in that order. + * For instance, to add three bits of value 1, 1 and 0, the unsigned + * integer will have value 192 (1*128 + 1*64 + 0*32) and the bit count + * will be 3. + * + * The SPH_SIZE_XXX macro is defined for each hash function; + * it evaluates to the function output size, expressed in bits. For instance, + * SPH_SIZE_sha1 evaluates to 160. + * + * When closed, the context is automatically reinitialized and can be + * immediately used for another computation. It is not necessary to call + * sph_XXX_init() after a close. Note that + * sph_XXX_init() can still be called to "reset" a context, + * i.e. forget previously input data, and get back to the initial state. + * + * @subsection alignment Data alignment + * + * "Alignment" is a property of data, which is said to be "properly + * aligned" when its emplacement in memory is such that the data can + * be optimally read by full words. This depends on the type of access; + * basically, some hash functions will read data by 32-bit or 64-bit + * words. sphlib does not mandate such alignment for input + * data, but using aligned data can substantially improve performance. + * + * As a rule, it is best to input data by chunks whose length (in bytes) + * is a multiple of eight, and which begins at "generally aligned" + * addresses, such as the base address returned by a call to + * malloc(). + * + * @section functions Implemented functions + * + * We give here the list of implemented functions. They are grouped by + * family; to each family corresponds a specific header file. Each + * individual function has its associated "short name". Please refer to + * the documentation for that header file to get details on the hash + * function denomination and provenance. + * + * Note: the functions marked with a '(64)' in the list below are + * available only if the C compiler provides an integer type of length + * 64 bits or more. Such a type is mandatory in the latest C standard + * (ISO 9899:1999, aka "C99") and is present in several older compilers + * as well, so chances are that such a type is available. + * + * - HAVAL family: file sph_haval.h + * - HAVAL-128/3 (128-bit, 3 passes): short name: haval128_3 + * - HAVAL-128/4 (128-bit, 4 passes): short name: haval128_4 + * - HAVAL-128/5 (128-bit, 5 passes): short name: haval128_5 + * - HAVAL-160/3 (160-bit, 3 passes): short name: haval160_3 + * - HAVAL-160/4 (160-bit, 4 passes): short name: haval160_4 + * - HAVAL-160/5 (160-bit, 5 passes): short name: haval160_5 + * - HAVAL-192/3 (192-bit, 3 passes): short name: haval192_3 + * - HAVAL-192/4 (192-bit, 4 passes): short name: haval192_4 + * - HAVAL-192/5 (192-bit, 5 passes): short name: haval192_5 + * - HAVAL-224/3 (224-bit, 3 passes): short name: haval224_3 + * - HAVAL-224/4 (224-bit, 4 passes): short name: haval224_4 + * - HAVAL-224/5 (224-bit, 5 passes): short name: haval224_5 + * - HAVAL-256/3 (256-bit, 3 passes): short name: haval256_3 + * - HAVAL-256/4 (256-bit, 4 passes): short name: haval256_4 + * - HAVAL-256/5 (256-bit, 5 passes): short name: haval256_5 + * - MD2: file sph_md2.h, short name: md2 + * - MD4: file sph_md4.h, short name: md4 + * - MD5: file sph_md5.h, short name: md5 + * - PANAMA: file sph_panama.h, short name: panama + * - RadioGatun family: file sph_radiogatun.h + * - RadioGatun[32]: short name: radiogatun32 + * - RadioGatun[64]: short name: radiogatun64 (64) + * - RIPEMD family: file sph_ripemd.h + * - RIPEMD: short name: ripemd + * - RIPEMD-128: short name: ripemd128 + * - RIPEMD-160: short name: ripemd160 + * - SHA-0: file sph_sha0.h, short name: sha0 + * - SHA-1: file sph_sha1.h, short name: sha1 + * - SHA-2 family, 32-bit hashes: file sph_sha2.h + * - SHA-224: short name: sha224 + * - SHA-256: short name: sha256 + * - SHA-384: short name: sha384 (64) + * - SHA-512: short name: sha512 (64) + * - Tiger family: file sph_tiger.h + * - Tiger: short name: tiger (64) + * - Tiger2: short name: tiger2 (64) + * - WHIRLPOOL family: file sph_whirlpool.h + * - WHIRLPOOL-0: short name: whirlpool0 (64) + * - WHIRLPOOL-1: short name: whirlpool1 (64) + * - WHIRLPOOL: short name: whirlpool (64) + * + * The fourteen second-round SHA-3 candidates are also implemented; + * when applicable, the implementations follow the "final" specifications + * as published for the third round of the SHA-3 competition (BLAKE, + * Groestl, JH, Keccak and Skein have been tweaked for third round). + * + * - BLAKE family: file sph_blake.h + * - BLAKE-224: short name: blake224 + * - BLAKE-256: short name: blake256 + * - BLAKE-384: short name: blake384 + * - BLAKE-512: short name: blake512 + * - BMW (Blue Midnight Wish) family: file sph_bmw.h + * - BMW-224: short name: bmw224 + * - BMW-256: short name: bmw256 + * - BMW-384: short name: bmw384 (64) + * - BMW-512: short name: bmw512 (64) + * - CubeHash family: file sph_cubehash.h (specified as + * CubeHash16/32 in the CubeHash specification) + * - CubeHash-224: short name: cubehash224 + * - CubeHash-256: short name: cubehash256 + * - CubeHash-384: short name: cubehash384 + * - CubeHash-512: short name: cubehash512 + * - ECHO family: file sph_echo.h + * - ECHO-224: short name: echo224 + * - ECHO-256: short name: echo256 + * - ECHO-384: short name: echo384 + * - ECHO-512: short name: echo512 + * - Fugue family: file sph_fugue.h + * - Fugue-224: short name: fugue224 + * - Fugue-256: short name: fugue256 + * - Fugue-384: short name: fugue384 + * - Fugue-512: short name: fugue512 + * - Groestl family: file sph_groestl.h + * - Groestl-224: short name: groestl224 + * - Groestl-256: short name: groestl256 + * - Groestl-384: short name: groestl384 + * - Groestl-512: short name: groestl512 + * - Hamsi family: file sph_hamsi.h + * - Hamsi-224: short name: hamsi224 + * - Hamsi-256: short name: hamsi256 + * - Hamsi-384: short name: hamsi384 + * - Hamsi-512: short name: hamsi512 + * - JH family: file sph_jh.h + * - JH-224: short name: jh224 + * - JH-256: short name: jh256 + * - JH-384: short name: jh384 + * - JH-512: short name: jh512 + * - Keccak family: file sph_keccak.h + * - Keccak-224: short name: keccak224 + * - Keccak-256: short name: keccak256 + * - Keccak-384: short name: keccak384 + * - Keccak-512: short name: keccak512 + * - Luffa family: file sph_luffa.h + * - Luffa-224: short name: luffa224 + * - Luffa-256: short name: luffa256 + * - Luffa-384: short name: luffa384 + * - Luffa-512: short name: luffa512 + * - Shabal family: file sph_shabal.h + * - Shabal-192: short name: shabal192 + * - Shabal-224: short name: shabal224 + * - Shabal-256: short name: shabal256 + * - Shabal-384: short name: shabal384 + * - Shabal-512: short name: shabal512 + * - SHAvite-3 family: file sph_shavite.h + * - SHAvite-224 (nominally "SHAvite-3 with 224-bit output"): + * short name: shabal224 + * - SHAvite-256 (nominally "SHAvite-3 with 256-bit output"): + * short name: shabal256 + * - SHAvite-384 (nominally "SHAvite-3 with 384-bit output"): + * short name: shabal384 + * - SHAvite-512 (nominally "SHAvite-3 with 512-bit output"): + * short name: shabal512 + * - SIMD family: file sph_simd.h + * - SIMD-224: short name: simd224 + * - SIMD-256: short name: simd256 + * - SIMD-384: short name: simd384 + * - SIMD-512: short name: simd512 + * - Skein family: file sph_skein.h + * - Skein-224 (nominally specified as Skein-512-224): short name: + * skein224 (64) + * - Skein-256 (nominally specified as Skein-512-256): short name: + * skein256 (64) + * - Skein-384 (nominally specified as Skein-512-384): short name: + * skein384 (64) + * - Skein-512 (nominally specified as Skein-512-512): short name: + * skein512 (64) + * + * For the second-round SHA-3 candidates, the functions are as specified + * for round 2, i.e. with the "tweaks" that some candidates added + * between round 1 and round 2. Also, some of the submitted packages for + * round 2 contained errors, in the specification, reference code, or + * both. sphlib implements the corrected versions. + */ + +/** @hideinitializer + * Unsigned integer type whose length is at least 32 bits; on most + * architectures, it will have a width of exactly 32 bits. Unsigned C + * types implement arithmetics modulo a power of 2; use the + * SPH_T32() macro to ensure that the value is truncated + * to exactly 32 bits. Unless otherwise specified, all macros and + * functions which accept sph_u32 values assume that these + * values fit on 32 bits, i.e. do not exceed 2^32-1, even on architectures + * where sph_u32 is larger than that. + */ +typedef __arch_dependant__ sph_u32; + +/** @hideinitializer + * Signed integer type corresponding to sph_u32; it has + * width 32 bits or more. + */ +typedef __arch_dependant__ sph_s32; + +/** @hideinitializer + * Unsigned integer type whose length is at least 64 bits; on most + * architectures which feature such a type, it will have a width of + * exactly 64 bits. C99-compliant platform will have this type; it + * is also defined when the GNU compiler (gcc) is used, and on + * platforms where unsigned long is large enough. If this + * type is not available, then some hash functions which depends on + * a 64-bit type will not be available (most notably SHA-384, SHA-512, + * Tiger and WHIRLPOOL). + */ +typedef __arch_dependant__ sph_u64; + +/** @hideinitializer + * Signed integer type corresponding to sph_u64; it has + * width 64 bits or more. + */ +typedef __arch_dependant__ sph_s64; + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u32. Depending on + * how this type is defined, a suffix such as UL may + * be appended to the argument. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C32(x) + +/** + * Truncate a 32-bit value to exactly 32 bits. On most systems, this is + * a no-op, recognized as such by the compiler. + * + * @param x the value to truncate (of type sph_u32) + */ +#define SPH_T32(x) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTL32(x, n) + +/** + * Rotate a 32-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 31. This macro assumes that its + * first argument fits in 32 bits (no extra bit allowed on machines where + * sph_u32 is wider); both arguments may be evaluated + * several times. + * + * @param x the value to rotate (of type sph_u32) + * @param n the rotation count (between 1 and 31, inclusive) + */ +#define SPH_ROTR32(x, n) + +/** + * This macro is defined on systems for which a 64-bit type has been + * detected, and is used for sph_u64. + */ +#define SPH_64 + +/** + * This macro is defined on systems for the "native" integer size is + * 64 bits (64-bit values fit in one register). + */ +#define SPH_64_TRUE + +/** + * This macro expands the token x into a suitable + * constant expression of type sph_u64. Depending on + * how this type is defined, a suffix such as ULL may + * be appended to the argument. This macro is defined only if a + * 64-bit type was detected and used for sph_u64. + * + * @param x the token to expand into a suitable constant expression + */ +#define SPH_C64(x) + +/** + * Truncate a 64-bit value to exactly 64 bits. On most systems, this is + * a no-op, recognized as such by the compiler. This macro is defined only + * if a 64-bit type was detected and used for sph_u64. + * + * @param x the value to truncate (of type sph_u64) + */ +#define SPH_T64(x) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTL64(x, n) + +/** + * Rotate a 64-bit value by a number of bits to the left. The rotate + * count must reside between 1 and 63. This macro assumes that its + * first argument fits in 64 bits (no extra bit allowed on machines where + * sph_u64 is wider); both arguments may be evaluated + * several times. This macro is defined only if a 64-bit type was detected + * and used for sph_u64. + * + * @param x the value to rotate (of type sph_u64) + * @param n the rotation count (between 1 and 63, inclusive) + */ +#define SPH_ROTR64(x, n) + +/** + * This macro evaluates to inline or an equivalent construction, + * if available on the compilation platform, or to nothing otherwise. This + * is used to declare inline functions, for which the compiler should + * endeavour to include the code directly in the caller. Inline functions + * are typically defined in header files as replacement for macros. + */ +#define SPH_INLINE + +/** + * This macro is defined if the platform has been detected as using + * little-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_LITTLE_ENDIAN + +/** + * This macro is defined if the platform has been detected as using + * big-endian convention. This implies that the sph_u32 + * type (and the sph_u64 type also, if it is defined) has + * an exact width (i.e. exactly 32-bit, respectively 64-bit). + */ +#define SPH_BIG_ENDIAN + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in little-endian + * convention. This is the case for little-endian platforms, and also + * for the big-endian platforms which have special little-endian access + * opcodes (e.g. Ultrasparc). + */ +#define SPH_LITTLE_FAST + +/** + * This macro is defined if 32-bit words (and 64-bit words, if defined) + * can be read from and written to memory efficiently in big-endian + * convention. This is the case for little-endian platforms, and also + * for the little-endian platforms which have special big-endian access + * opcodes. + */ +#define SPH_BIG_FAST + +/** + * On some platforms, this macro is defined to an unsigned integer type + * into which pointer values may be cast. The resulting value can then + * be tested for being a multiple of 2, 4 or 8, indicating an aligned + * pointer for, respectively, 16-bit, 32-bit or 64-bit memory accesses. + */ +#define SPH_UPTR + +/** + * When defined, this macro indicates that unaligned memory accesses + * are possible with only a minor penalty, and thus should be prefered + * over strategies which first copy data to an aligned buffer. + */ +#define SPH_UNALIGNED + +/** + * Byte-swap a 32-bit word (i.e. 0x12345678 becomes + * 0x78563412). This is an inline function which resorts + * to inline assembly on some platforms, for better performance. + * + * @param x the 32-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u32 sph_bswap32(sph_u32 x); + +/** + * Byte-swap a 64-bit word. This is an inline function which resorts + * to inline assembly on some platforms, for better performance. This + * function is defined only if a suitable 64-bit type was found for + * sph_u64 + * + * @param x the 64-bit value to byte-swap + * @return the byte-swapped value + */ +static inline sph_u64 sph_bswap64(sph_u64 x); + +/** + * Decode a 16-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16le(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16le(void *dst, unsigned val); + +/** + * Decode a 16-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline unsigned sph_dec16be(const void *src); + +/** + * Encode a 16-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc16be(void *dst, unsigned val); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32le() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32le_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32le() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32le_aligned(void *dst, sph_u32 val); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be(const void *src); + +/** + * Decode a 32-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec32be() function. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u32 sph_dec32be_aligned(const void *src); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be(void *dst, sph_u32 val); + +/** + * Encode a 32-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc32be() function. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc32be_aligned(void *dst, sph_u32 val); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64le() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64le_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in little-endian convention + * (least significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64le() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64le_aligned(void *dst, sph_u64 val); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be(const void *src); + +/** + * Decode a 64-bit unsigned value from memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * source address is suitably aligned for a direct access, if the platform + * supports such things; it can thus be marginally faster than the generic + * sph_dec64be() function. This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param src the source address + * @return the decoded value + */ +static inline sph_u64 sph_dec64be_aligned(const void *src); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function is defined only + * if a suitable 64-bit type was detected and used for sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be(void *dst, sph_u64 val); + +/** + * Encode a 64-bit unsigned value into memory, in big-endian convention + * (most significant byte comes first). This function assumes that the + * destination address is suitably aligned for a direct access, if the + * platform supports such things; it can thus be marginally faster than + * the generic sph_enc64be() function. This function is defined + * only if a suitable 64-bit type was detected and used for + * sph_u64. + * + * @param dst the destination buffer + * @param val the value to encode + */ +static inline void sph_enc64be_aligned(void *dst, sph_u64 val); + +#endif + +/* ============== END documentation block for Doxygen ============= */ + +#ifndef DOXYGEN_IGNORE + +/* + * We want to define the types "sph_u32" and "sph_u64" which hold + * unsigned values of at least, respectively, 32 and 64 bits. These + * tests should select appropriate types for most platforms. The + * macro "SPH_64" is defined if the 64-bit is supported. + */ + +#undef SPH_64 +#undef SPH_64_TRUE + +#if defined __STDC__ && __STDC_VERSION__ >= 199901L + +/* + * On C99 implementations, we can use to get an exact 64-bit + * type, if any, or otherwise use a wider type (which must exist, for + * C99 conformance). + */ + +#include + +#ifdef UINT32_MAX +typedef uint32_t sph_u32; +typedef int32_t sph_s32; +#else +typedef uint_fast32_t sph_u32; +typedef int_fast32_t sph_s32; +#endif +#if !SPH_NO_64 +#ifdef UINT64_MAX +typedef uint64_t sph_u64; +typedef int64_t sph_s64; +#else +typedef uint_fast64_t sph_u64; +typedef int_fast64_t sph_s64; +#endif +#endif + +#define SPH_C32(x) ((sph_u32)(x)) +#if !SPH_NO_64 +#define SPH_C64(x) ((sph_u64)(x)) +#define SPH_64 1 +#endif + +#else + +/* + * On non-C99 systems, we use "unsigned int" if it is wide enough, + * "unsigned long" otherwise. This supports all "reasonable" architectures. + * We have to be cautious: pre-C99 preprocessors handle constants + * differently in '#if' expressions. Hence the shifts to test UINT_MAX. + */ + +#if ((UINT_MAX >> 11) >> 11) >= 0x3FF + +typedef unsigned int sph_u32; +typedef int sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## U)) + +#else + +typedef unsigned long sph_u32; +typedef long sph_s32; + +#define SPH_C32(x) ((sph_u32)(x ## UL)) + +#endif + +#if !SPH_NO_64 + +/* + * We want a 64-bit type. We use "unsigned long" if it is wide enough (as + * is common on 64-bit architectures such as AMD64, Alpha or Sparcv9), + * "unsigned long long" otherwise, if available. We use ULLONG_MAX to + * test whether "unsigned long long" is available; we also know that + * gcc features this type, even if the libc header do not know it. + */ + +#if ((ULONG_MAX >> 31) >> 31) >= 3 + +typedef unsigned long sph_u64; +typedef long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## UL)) + +#define SPH_64 1 + +#elif ((ULLONG_MAX >> 31) >> 31) >= 3 || defined __GNUC__ + +typedef unsigned long long sph_u64; +typedef long long sph_s64; + +#define SPH_C64(x) ((sph_u64)(x ## ULL)) + +#define SPH_64 1 + +#else + +/* + * No 64-bit type... + */ + +#endif + +#endif + +#endif + +/* + * If the "unsigned long" type has length 64 bits or more, then this is + * a "true" 64-bit architectures. This is also true with Visual C on + * amd64, even though the "long" type is limited to 32 bits. + */ +#if SPH_64 && (((ULONG_MAX >> 31) >> 31) >= 3 || defined _M_X64) +#define SPH_64_TRUE 1 +#endif + +/* + * Implementation note: some processors have specific opcodes to perform + * a rotation. Recent versions of gcc recognize the expression above and + * use the relevant opcodes, when appropriate. + */ + +#define SPH_T32(x) ((x) & SPH_C32(0xFFFFFFFF)) +#define SPH_ROTL32(x, n) SPH_T32(((x) << (n)) | ((x) >> (32 - (n)))) +#define SPH_ROTR32(x, n) SPH_ROTL32(x, (32 - (n))) + +#if SPH_64 + +#define SPH_T64(x) ((x) & SPH_C64(0xFFFFFFFFFFFFFFFF)) +#define SPH_ROTL64(x, n) SPH_T64(((x) << (n)) | ((x) >> (64 - (n)))) +#define SPH_ROTR64(x, n) SPH_ROTL64(x, (64 - (n))) + +#endif + +#ifndef DOXYGEN_IGNORE +/* + * Define SPH_INLINE to be an "inline" qualifier, if available. We define + * some small macro-like functions which benefit greatly from being inlined. + */ +#if (defined __STDC__ && __STDC_VERSION__ >= 199901L) || defined __GNUC__ +#define SPH_INLINE inline +#elif defined _MSC_VER +#define SPH_INLINE __inline +#else +#define SPH_INLINE +#endif +#endif + +/* + * We define some macros which qualify the architecture. These macros + * may be explicit set externally (e.g. as compiler parameters). The + * code below sets those macros if they are not already defined. + * + * Most macros are boolean, thus evaluate to either zero or non-zero. + * The SPH_UPTR macro is special, in that it evaluates to a C type, + * or is not defined. + * + * SPH_UPTR if defined: unsigned type to cast pointers into + * + * SPH_UNALIGNED non-zero if unaligned accesses are efficient + * SPH_LITTLE_ENDIAN non-zero if architecture is known to be little-endian + * SPH_BIG_ENDIAN non-zero if architecture is known to be big-endian + * SPH_LITTLE_FAST non-zero if little-endian decoding is fast + * SPH_BIG_FAST non-zero if big-endian decoding is fast + * + * If SPH_UPTR is defined, then encoding and decoding of 32-bit and 64-bit + * values will try to be "smart". Either SPH_LITTLE_ENDIAN or SPH_BIG_ENDIAN + * _must_ be non-zero in those situations. The 32-bit and 64-bit types + * _must_ also have an exact width. + * + * SPH_SPARCV9_GCC_32 UltraSPARC-compatible with gcc, 32-bit mode + * SPH_SPARCV9_GCC_64 UltraSPARC-compatible with gcc, 64-bit mode + * SPH_SPARCV9_GCC UltraSPARC-compatible with gcc + * SPH_I386_GCC x86-compatible (32-bit) with gcc + * SPH_I386_MSVC x86-compatible (32-bit) with Microsoft Visual C + * SPH_AMD64_GCC x86-compatible (64-bit) with gcc + * SPH_AMD64_MSVC x86-compatible (64-bit) with Microsoft Visual C + * SPH_PPC32_GCC PowerPC, 32-bit, with gcc + * SPH_PPC64_GCC PowerPC, 64-bit, with gcc + * + * TODO: enhance automatic detection, for more architectures and compilers. + * Endianness is the most important. SPH_UNALIGNED and SPH_UPTR help with + * some very fast functions (e.g. MD4) when using unaligned input data. + * The CPU-specific-with-GCC macros are useful only for inline assembly, + * normally restrained to this header file. + */ + +/* + * 32-bit x86, aka "i386 compatible". + */ +#if defined __i386__ || defined _M_IX86 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#ifdef __GNUC__ +#define SPH_DETECT_I386_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_I386_MSVC 1 +#endif + +/* + * 64-bit x86, hereafter known as "amd64". + */ +#elif defined __x86_64 || defined _M_X64 + +#define SPH_DETECT_UNALIGNED 1 +#define SPH_DETECT_LITTLE_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_AMD64_GCC 1 +#endif +#ifdef _MSC_VER +#define SPH_DETECT_AMD64_MSVC 1 +#endif + +/* + * 64-bit Sparc architecture (implies v9). + */ +#elif ((defined __sparc__ || defined __sparc) && defined __arch64__) \ + || defined __sparcv9 + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u64 +#ifdef __GNUC__ +#define SPH_DETECT_SPARCV9_GCC_64 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * 32-bit Sparc. + */ +#elif (defined __sparc__ || defined __sparc) \ + && !(defined __sparcv9 || defined __arch64__) + +#define SPH_DETECT_BIG_ENDIAN 1 +#define SPH_DETECT_UPTR sph_u32 +#if defined __GNUC__ && defined __sparc_v9__ +#define SPH_DETECT_SPARCV9_GCC_32 1 +#define SPH_DETECT_LITTLE_FAST 1 +#endif + +/* + * ARM, little-endian. + */ +#elif defined __arm__ && __ARMEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, little-endian. + */ +#elif MIPSEL || _MIPSEL || __MIPSEL || __MIPSEL__ + +#define SPH_DETECT_LITTLE_ENDIAN 1 + +/* + * MIPS, big-endian. + */ +#elif MIPSEB || _MIPSEB || __MIPSEB || __MIPSEB__ + +#define SPH_DETECT_BIG_ENDIAN 1 + +/* + * PowerPC. + */ +#elif defined __powerpc__ || defined __POWERPC__ || defined __ppc__ \ + || defined _ARCH_PPC + +/* + * Note: we do not declare cross-endian access to be "fast": even if + * using inline assembly, implementation should still assume that + * keeping the decoded word in a temporary is faster than decoding + * it again. + */ +#if defined __GNUC__ +#if SPH_64_TRUE +#define SPH_DETECT_PPC64_GCC 1 +#else +#define SPH_DETECT_PPC32_GCC 1 +#endif +#endif + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif + +/* + * Itanium, 64-bit. + */ +#elif defined __ia64 || defined __ia64__ \ + || defined __itanium__ || defined _M_IA64 + +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN +#define SPH_DETECT_BIG_ENDIAN 1 +#else +#define SPH_DETECT_LITTLE_ENDIAN 1 +#endif +#if defined __LP64__ || defined _LP64 +#define SPH_DETECT_UPTR sph_u64 +#else +#define SPH_DETECT_UPTR sph_u32 +#endif + +#endif + +#if defined SPH_DETECT_SPARCV9_GCC_32 || defined SPH_DETECT_SPARCV9_GCC_64 +#define SPH_DETECT_SPARCV9_GCC 1 +#endif + +#if defined SPH_DETECT_UNALIGNED && !defined SPH_UNALIGNED +#define SPH_UNALIGNED SPH_DETECT_UNALIGNED +#endif +#if defined SPH_DETECT_UPTR && !defined SPH_UPTR +#define SPH_UPTR SPH_DETECT_UPTR +#endif +#if defined SPH_DETECT_LITTLE_ENDIAN && !defined SPH_LITTLE_ENDIAN +#define SPH_LITTLE_ENDIAN SPH_DETECT_LITTLE_ENDIAN +#endif +#if defined SPH_DETECT_BIG_ENDIAN && !defined SPH_BIG_ENDIAN +#define SPH_BIG_ENDIAN SPH_DETECT_BIG_ENDIAN +#endif +#if defined SPH_DETECT_LITTLE_FAST && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST SPH_DETECT_LITTLE_FAST +#endif +#if defined SPH_DETECT_BIG_FAST && !defined SPH_BIG_FAST +#define SPH_BIG_FAST SPH_DETECT_BIG_FAST +#endif +#if defined SPH_DETECT_SPARCV9_GCC_32 && !defined SPH_SPARCV9_GCC_32 +#define SPH_SPARCV9_GCC_32 SPH_DETECT_SPARCV9_GCC_32 +#endif +#if defined SPH_DETECT_SPARCV9_GCC_64 && !defined SPH_SPARCV9_GCC_64 +#define SPH_SPARCV9_GCC_64 SPH_DETECT_SPARCV9_GCC_64 +#endif +#if defined SPH_DETECT_SPARCV9_GCC && !defined SPH_SPARCV9_GCC +#define SPH_SPARCV9_GCC SPH_DETECT_SPARCV9_GCC +#endif +#if defined SPH_DETECT_I386_GCC && !defined SPH_I386_GCC +#define SPH_I386_GCC SPH_DETECT_I386_GCC +#endif +#if defined SPH_DETECT_I386_MSVC && !defined SPH_I386_MSVC +#define SPH_I386_MSVC SPH_DETECT_I386_MSVC +#endif +#if defined SPH_DETECT_AMD64_GCC && !defined SPH_AMD64_GCC +#define SPH_AMD64_GCC SPH_DETECT_AMD64_GCC +#endif +#if defined SPH_DETECT_AMD64_MSVC && !defined SPH_AMD64_MSVC +#define SPH_AMD64_MSVC SPH_DETECT_AMD64_MSVC +#endif +#if defined SPH_DETECT_PPC32_GCC && !defined SPH_PPC32_GCC +#define SPH_PPC32_GCC SPH_DETECT_PPC32_GCC +#endif +#if defined SPH_DETECT_PPC64_GCC && !defined SPH_PPC64_GCC +#define SPH_PPC64_GCC SPH_DETECT_PPC64_GCC +#endif + +#if SPH_LITTLE_ENDIAN && !defined SPH_LITTLE_FAST +#define SPH_LITTLE_FAST 1 +#endif +#if SPH_BIG_ENDIAN && !defined SPH_BIG_FAST +#define SPH_BIG_FAST 1 +#endif + +#if defined SPH_UPTR && !(SPH_LITTLE_ENDIAN || SPH_BIG_ENDIAN) +#error SPH_UPTR defined, but endianness is not known. +#endif + +#if SPH_I386_GCC && !SPH_NO_ASM + +/* + * On x86 32-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + +#elif SPH_AMD64_GCC && !SPH_NO_ASM + +/* + * On x86 64-bit, with gcc, we use the bswapl opcode to byte-swap 32-bit + * and 64-bit values. + */ + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + __asm__ __volatile__ ("bswapl %0" : "=r" (x) : "0" (x)); + return x; +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + __asm__ __volatile__ ("bswapq %0" : "=r" (x) : "0" (x)); + return x; +} + +#endif + +/* + * Disabled code. Apparently, Microsoft Visual C 2005 is smart enough + * to generate proper opcodes for endianness swapping with the pure C + * implementation below. + * + +#elif SPH_I386_MSVC && !SPH_NO_ASM + +static __inline sph_u32 __declspec(naked) __fastcall +sph_bswap32(sph_u32 x) +{ + __asm { + bswap ecx + mov eax,ecx + ret + } +} + +#if SPH_64 + +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + return ((sph_u64)sph_bswap32((sph_u32)x) << 32) + | (sph_u64)sph_bswap32((sph_u32)(x >> 32)); +} + +#endif + + * + * [end of disabled code] + */ + +#else + +static SPH_INLINE sph_u32 +sph_bswap32(sph_u32 x) +{ + x = SPH_T32((x << 16) | (x >> 16)); + x = ((x & SPH_C32(0xFF00FF00)) >> 8) + | ((x & SPH_C32(0x00FF00FF)) << 8); + return x; +} + +#if SPH_64 + +/** + * Byte-swap a 64-bit value. + * + * @param x the input value + * @return the byte-swapped value + */ +static SPH_INLINE sph_u64 +sph_bswap64(sph_u64 x) +{ + x = SPH_T64((x << 32) | (x >> 32)); + x = ((x & SPH_C64(0xFFFF0000FFFF0000)) >> 16) + | ((x & SPH_C64(0x0000FFFF0000FFFF)) << 16); + x = ((x & SPH_C64(0xFF00FF00FF00FF00)) >> 8) + | ((x & SPH_C64(0x00FF00FF00FF00FF)) << 8); + return x; +} + +#endif + +#endif + +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + +/* + * On UltraSPARC systems, native ordering is big-endian, but it is + * possible to perform little-endian read accesses by specifying the + * address space 0x88 (ASI_PRIMARY_LITTLE). Basically, either we use + * the opcode "lda [%reg]0x88,%dst", where %reg is the register which + * contains the source address and %dst is the destination register, + * or we use "lda [%reg+imm]%asi,%dst", which uses the %asi register + * to get the address space name. The latter format is better since it + * combines an addition and the actual access in a single opcode; but + * it requires the setting (and subsequent resetting) of %asi, which is + * slow. Some operations (i.e. MD5 compression function) combine many + * successive little-endian read accesses, which may share the same + * %asi setting. The macros below contain the appropriate inline + * assembly. + */ + +#define SPH_SPARCV9_SET_ASI \ + sph_u32 sph_sparcv9_asi; \ + __asm__ __volatile__ ( \ + "rd %%asi,%0\n\twr %%g0,0x88,%%asi" : "=r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_RESET_ASI \ + __asm__ __volatile__ ("wr %%g0,%0,%%asi" : : "r" (sph_sparcv9_asi)); + +#define SPH_SPARCV9_DEC32LE(base, idx) ({ \ + sph_u32 sph_sparcv9_tmp; \ + __asm__ __volatile__ ("lda [%1+" #idx "*4]%%asi,%0" \ + : "=r" (sph_sparcv9_tmp) : "r" (base)); \ + sph_sparcv9_tmp; \ + }) + +#endif + +static SPH_INLINE void +sph_enc16be(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = (val >> 8); + ((unsigned char *)dst)[1] = val; +} + +static SPH_INLINE unsigned +sph_dec16be(const void *src) +{ + return ((unsigned)(((const unsigned char *)src)[0]) << 8) + | (unsigned)(((const unsigned char *)src)[1]); +} + +static SPH_INLINE void +sph_enc16le(void *dst, unsigned val) +{ + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = val >> 8; +} + +static SPH_INLINE unsigned +sph_dec16le(const void *src) +{ + return (unsigned)(((const unsigned char *)src)[0]) + | ((unsigned)(((const unsigned char *)src)[1]) << 8); +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32be(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32be_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 24); + ((unsigned char *)dst)[1] = (val >> 16); + ((unsigned char *)dst)[2] = (val >> 8); + ((unsigned char *)dst)[3] = val; +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif + } else { + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); + } +#endif +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u32 *)src; +#else + return ((sph_u32)(((const unsigned char *)src)[0]) << 24) + | ((sph_u32)(((const unsigned char *)src)[1]) << 16) + | ((sph_u32)(((const unsigned char *)src)[2]) << 8) + | (sph_u32)(((const unsigned char *)src)[3]); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 32-bit value to encode + */ +static SPH_INLINE void +sph_enc32le(void *dst, sph_u32 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; +#else + if (((SPH_UPTR)dst & 3) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap32(val); +#endif + *(sph_u32 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Encode a 32-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (32-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc32le_aligned(void *dst, sph_u32 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u32 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u32 *)dst = sph_bswap32(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap32(*(const sph_u32 *)src); +#else + return *(const sph_u32 *)src; +#endif +#else + if (((SPH_UPTR)src & 3) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + /* + * "__volatile__" is needed here because without it, + * gcc-3.4.3 miscompiles the code and performs the + * access before the test on the address, thus triggering + * a bus error... + */ + __asm__ __volatile__ ( + "lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * On PowerPC, this turns out not to be worth the effort: the inline + * assembly makes GCC optimizer uncomfortable, which tends to nullify + * the decoding gains. + * + * For most hash functions, using this inline assembly trick changes + * hashing speed by less than 5% and often _reduces_ it. The biggest + * gains are for MD4 (+11%) and CubeHash (+30%). For all others, it is + * less then 10%. The speed gain on CubeHash is probably due to the + * chronic shortage of registers that CubeHash endures; for the other + * functions, the generic code appears to be efficient enough already. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ( + "lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return *(const sph_u32 *)src; +#endif + } else { + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); + } +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +/** + * Decode a 32-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (32-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u32 +sph_dec32le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u32 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lda [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif (SPH_PPC32_GCC || SPH_PPC64_GCC) && !SPH_NO_ASM + sph_u32 tmp; + + __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap32(*(const sph_u32 *)src); +#endif +#else + return (sph_u32)(((const unsigned char *)src)[0]) + | ((sph_u32)(((const unsigned char *)src)[1]) << 8) + | ((sph_u32)(((const unsigned char *)src)[2]) << 16) + | ((sph_u32)(((const unsigned char *)src)[3]) << 24); +#endif +} + +#if SPH_64 + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64be(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_LITTLE_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; + } +#endif +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (big endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64be_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = val; +#else + ((unsigned char *)dst)[0] = (val >> 56); + ((unsigned char *)dst)[1] = (val >> 48); + ((unsigned char *)dst)[2] = (val >> 40); + ((unsigned char *)dst)[3] = (val >> 32); + ((unsigned char *)dst)[4] = (val >> 24); + ((unsigned char *)dst)[5] = (val >> 16); + ((unsigned char *)dst)[6] = (val >> 8); + ((unsigned char *)dst)[7] = val; +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif + } else { + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); + } +#endif +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (big endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64be_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#elif SPH_BIG_ENDIAN + return *(const sph_u64 *)src; +#else + return ((sph_u64)(((const unsigned char *)src)[0]) << 56) + | ((sph_u64)(((const unsigned char *)src)[1]) << 48) + | ((sph_u64)(((const unsigned char *)src)[2]) << 40) + | ((sph_u64)(((const unsigned char *)src)[3]) << 32) + | ((sph_u64)(((const unsigned char *)src)[4]) << 24) + | ((sph_u64)(((const unsigned char *)src)[5]) << 16) + | ((sph_u64)(((const unsigned char *)src)[6]) << 8) + | (sph_u64)(((const unsigned char *)src)[7]); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * + * @param dst the destination buffer + * @param val the 64-bit value to encode + */ +static SPH_INLINE void +sph_enc64le(void *dst, sph_u64 val) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; +#else + if (((SPH_UPTR)dst & 7) == 0) { +#if SPH_BIG_ENDIAN + val = sph_bswap64(val); +#endif + *(sph_u64 *)dst = val; + } else { + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); + } +#endif +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Encode a 64-bit value into the provided buffer (little endian convention). + * The destination buffer must be properly aligned. + * + * @param dst the destination buffer (64-bit aligned) + * @param val the value to encode + */ +static SPH_INLINE void +sph_enc64le_aligned(void *dst, sph_u64 val) +{ +#if SPH_LITTLE_ENDIAN + *(sph_u64 *)dst = val; +#elif SPH_BIG_ENDIAN + *(sph_u64 *)dst = sph_bswap64(val); +#else + ((unsigned char *)dst)[0] = val; + ((unsigned char *)dst)[1] = (val >> 8); + ((unsigned char *)dst)[2] = (val >> 16); + ((unsigned char *)dst)[3] = (val >> 24); + ((unsigned char *)dst)[4] = (val >> 32); + ((unsigned char *)dst)[5] = (val >> 40); + ((unsigned char *)dst)[6] = (val >> 48); + ((unsigned char *)dst)[7] = (val >> 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * + * @param src the source buffer + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le(const void *src) +{ +#if defined SPH_UPTR +#if SPH_UNALIGNED +#if SPH_BIG_ENDIAN + return sph_bswap64(*(const sph_u64 *)src); +#else + return *(const sph_u64 *)src; +#endif +#else + if (((SPH_UPTR)src & 7) == 0) { +#if SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned( + (const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ( + "ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return *(const sph_u64 *)src; +#endif + } else { + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); + } +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +/** + * Decode a 64-bit value from the provided buffer (little endian convention). + * The source buffer must be properly aligned. + * + * @param src the source buffer (64-bit aligned) + * @return the decoded value + */ +static SPH_INLINE sph_u64 +sph_dec64le_aligned(const void *src) +{ +#if SPH_LITTLE_ENDIAN + return *(const sph_u64 *)src; +#elif SPH_BIG_ENDIAN +#if SPH_SPARCV9_GCC_64 && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldxa [%1]0x88,%0" : "=r" (tmp) : "r" (src)); + return tmp; +/* + * Not worth it generally. + * +#elif SPH_PPC32_GCC && !SPH_NO_ASM + return (sph_u64)sph_dec32le_aligned(src) + | ((sph_u64)sph_dec32le_aligned((const char *)src + 4) << 32); +#elif SPH_PPC64_GCC && !SPH_NO_ASM + sph_u64 tmp; + + __asm__ __volatile__ ("ldbrx %0,0,%1" : "=r" (tmp) : "r" (src)); + return tmp; + */ +#else + return sph_bswap64(*(const sph_u64 *)src); +#endif +#else + return (sph_u64)(((const unsigned char *)src)[0]) + | ((sph_u64)(((const unsigned char *)src)[1]) << 8) + | ((sph_u64)(((const unsigned char *)src)[2]) << 16) + | ((sph_u64)(((const unsigned char *)src)[3]) << 24) + | ((sph_u64)(((const unsigned char *)src)[4]) << 32) + | ((sph_u64)(((const unsigned char *)src)[5]) << 40) + | ((sph_u64)(((const unsigned char *)src)[6]) << 48) + | ((sph_u64)(((const unsigned char *)src)[7]) << 56); +#endif +} + +#endif + +#endif /* Doxygen excluded block */ + +#endif diff --git a/src/Native/libmultihash/yespower/insecure_memzero.h b/src/Native/libmultihash/yespower/insecure_memzero.h new file mode 100644 index 000000000..2fd97d866 --- /dev/null +++ b/src/Native/libmultihash/yespower/insecure_memzero.h @@ -0,0 +1 @@ +#define insecure_memzero(buf, len) /* empty */ \ No newline at end of file diff --git a/src/Native/libmultihash/yespower/sha256.h b/src/Native/libmultihash/yespower/sha256.h new file mode 100644 index 000000000..e2987b9f9 --- /dev/null +++ b/src/Native/libmultihash/yespower/sha256.h @@ -0,0 +1,129 @@ +/*- + * Copyright 2005-2016 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Use #defines in order to avoid namespace collisions with anyone else's + * SHA256 code (e.g., the code in OpenSSL). + */ +#define SHA256_Init libcperciva_SHA256_Init +#define SHA256_Update libcperciva_SHA256_Update +#define SHA256_Final libcperciva_SHA256_Final +#define SHA256_Buf libcperciva_SHA256_Buf +#define SHA256_CTX libcperciva_SHA256_CTX +#define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init +#define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update +#define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final +#define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf +#define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX + +/* Context structure for SHA256 operations. */ +typedef struct { + uint32_t state[8]; + uint64_t count; + uint8_t buf[64]; +} SHA256_CTX; + +/** + * SHA256_Init(ctx): + * Initialize the SHA256 context ${ctx}. + */ +void SHA256_Init(SHA256_CTX *); + +/** + * SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. + */ +void SHA256_Update(SHA256_CTX *, const void *, size_t); + +/** + * SHA256_Final(digest, ctx): + * Output the SHA256 hash of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void SHA256_Final(uint8_t[32], SHA256_CTX *); + +/** + * SHA256_Buf(in, len, digest): + * Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}. + */ +void SHA256_Buf(const void *, size_t, uint8_t[32]); + +/* Context structure for HMAC-SHA256 operations. */ +typedef struct { + SHA256_CTX ictx; + SHA256_CTX octx; +} HMAC_SHA256_CTX; + +/** + * HMAC_SHA256_Init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); + +/** + * HMAC_SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); + +/** + * HMAC_SHA256_Final(digest, ctx): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *); + +/** + * HMAC_SHA256_Buf(K, Klen, in, len, digest): + * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of + * length ${Klen}, and write the result to ${digest}. + */ +void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void YESPOWER_PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* !_SHA256_H_ */ \ No newline at end of file diff --git a/src/Native/libmultihash/yespower/sysendian.h b/src/Native/libmultihash/yespower/sysendian.h new file mode 100644 index 000000000..bf2215a39 --- /dev/null +++ b/src/Native/libmultihash/yespower/sysendian.h @@ -0,0 +1,94 @@ +/*- + * Copyright 2007-2014 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +#include + +/* Avoid namespace collisions with BSD . */ +#define be32dec libcperciva_be32dec +#define be32enc libcperciva_be32enc +#define be64enc libcperciva_be64enc +#define le32dec libcperciva_le32dec +#define le32enc libcperciva_le32enc + +static inline uint32_t +be32dec(const void * pp) +{ + const uint8_t * p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void * pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline void +be64enc(void * pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static inline uint32_t +le32dec(const void * pp) +{ + const uint8_t * p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void * pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +#endif /* !_SYSENDIAN_H_ */ \ No newline at end of file diff --git a/src/Native/libmultihash/yespower/yespower-blake2b.c b/src/Native/libmultihash/yespower/yespower-blake2b.c new file mode 100644 index 000000000..5a0b35d5f --- /dev/null +++ b/src/Native/libmultihash/yespower/yespower-blake2b.c @@ -0,0 +1,1207 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2012-2019 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + * + * This is a proof-of-work focused fork of yescrypt, including optimized and + * cut-down implementation of the obsolete yescrypt 0.5 (based off its first + * submission to PHC back in 2014) and a new proof-of-work specific variation + * known as yespower 1.0. The former is intended as an upgrade for + * cryptocurrencies that already use yescrypt 0.5 and the latter may be used + * as a further upgrade (hard fork) by those and other cryptocurrencies. The + * version of algorithm to use is requested through parameters, allowing for + * both algorithms to co-exist in client and miner implementations (such as in + * preparation for a hard-fork). + */ + +#ifndef _YESPOWER_OPT_C_PASS_ +#define _YESPOWER_OPT_C_PASS_ 1 +#endif + +#if _YESPOWER_OPT_C_PASS_ == 1 +/* + * AVX and especially XOP speed up Salsa20 a lot, but needlessly result in + * extra instruction prefixes for pwxform (which we make more use of). While + * no slowdown from the prefixes is generally observed on AMD CPUs supporting + * XOP, some slowdown is sometimes observed on Intel CPUs with AVX. + */ +#ifdef __XOP__ +#warning "Note: XOP is enabled. That's great." +#elif defined(__AVX__) +#warning "Note: AVX is enabled. That's OK." +#elif defined(__SSE2__) +#warning "Note: AVX and XOP are not enabled. That's OK." +#elif defined(__x86_64__) || defined(__i386__) +#warning "SSE2 not enabled. Expect poor performance." +#else +#warning "Note: building generic code for non-x86. That's OK." +#endif + +/* + * The SSE4 code version has fewer instructions than the generic SSE2 version, + * but all of the instructions are SIMD, thereby wasting the scalar execution + * units. Thus, the generic SSE2 version below actually runs faster on some + * CPUs due to its balanced mix of SIMD and scalar instructions. + */ +#undef USE_SSE4_FOR_32BIT + +#ifdef __SSE2__ +/* + * GCC before 4.9 would by default unnecessarily use store/load (without + * SSE4.1) or (V)PEXTR (with SSE4.1 or AVX) instead of simply (V)MOV. + * This was tracked as GCC bug 54349. + * "-mtune=corei7" works around this, but is only supported for GCC 4.6+. + * We use inline asm for pre-4.6 GCC, further down this file. + */ +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && __GNUC_MINOR__ < 9 && \ + !defined(__clang__) && !defined(__ICC) +#pragma GCC target ("tune=corei7") +#endif +#include +#ifdef __XOP__ +#include +#endif +#elif defined(__SSE__) +#include +#endif + +#include +#include +#include +#include + +#include "insecure_memzero.h" +#include "sysendian.h" +#include "crypto/blake2b-yp.h" + +#include "yespower.h" + +#ifdef __unix__ +#include +#endif + +#define HUGEPAGE_THRESHOLD (12 * 1024 * 1024) + +#ifdef __x86_64__ +#define HUGEPAGE_SIZE (2 * 1024 * 1024) +#else +#undef HUGEPAGE_SIZE +#endif + +static void *alloc_region(yespower_region_t *region, size_t size) +{ + size_t base_size = size; + uint8_t *base, *aligned; +#ifdef MAP_ANON + int flags = +#ifdef MAP_NOCORE + MAP_NOCORE | +#endif + MAP_ANON | MAP_PRIVATE; +#if defined(MAP_HUGETLB) && defined(HUGEPAGE_SIZE) + size_t new_size = size; + const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1; + if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) { + flags |= MAP_HUGETLB; +/* + * Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of + * huge page size, so let's round up to huge page size here. + */ + new_size = size + hugepage_mask; + new_size &= ~hugepage_mask; + } + base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, flags, -1, 0); + if (base != MAP_FAILED) { + base_size = new_size; + } else if (flags & MAP_HUGETLB) { + flags &= ~MAP_HUGETLB; + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + } + +#else + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); +#endif + if (base == MAP_FAILED) + base = NULL; + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **)&base, 64, size)) != 0) + base = NULL; + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) { + errno = ENOMEM; + } else if ((base = malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t)aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->base_size = base ? base_size : 0; + region->aligned_size = base ? size : 0; + return aligned; +} + +static inline void init_region(yespower_region_t *region) +{ + region->base = region->aligned = NULL; + region->base_size = region->aligned_size = 0; +} + +static int free_region(yespower_region_t *region) +{ + if (region->base) { +#ifdef MAP_ANON + if (munmap(region->base, region->base_size)) + return -1; +#else + free(region->base); +#endif + } + init_region(region); + return 0; +} + +#if __STDC_VERSION__ >= 199901L +/* Have restrict */ +#elif defined(__GNUC__) +#define restrict __restrict +#else +#define restrict +#endif + +#ifdef __GNUC__ +#define unlikely(exp) __builtin_expect(exp, 0) +#else +#define unlikely(exp) (exp) +#endif + +#ifdef __SSE__ +#define PREFETCH(x, hint) _mm_prefetch((const char *)(x), (hint)); +#else +#undef PREFETCH +#endif + +typedef union { + uint32_t w[16]; + uint64_t d[8]; +#ifdef __SSE2__ + __m128i q[4]; +#endif +} salsa20_blk_t; + +static inline void salsa20_simd_shuffle(const salsa20_blk_t *Bin, + salsa20_blk_t *Bout) +{ +#define COMBINE(out, in1, in2) \ + Bout->d[out] = Bin->w[in1 * 2] | ((uint64_t)Bin->w[in2 * 2 + 1] << 32); + COMBINE(0, 0, 2) + COMBINE(1, 5, 7) + COMBINE(2, 2, 4) + COMBINE(3, 7, 1) + COMBINE(4, 4, 6) + COMBINE(5, 1, 3) + COMBINE(6, 6, 0) + COMBINE(7, 3, 5) +#undef COMBINE +} + +static inline void salsa20_simd_unshuffle(const salsa20_blk_t *Bin, + salsa20_blk_t *Bout) +{ +#define UNCOMBINE(out, in1, in2) \ + Bout->w[out * 2] = Bin->d[in1]; \ + Bout->w[out * 2 + 1] = Bin->d[in2] >> 32; + UNCOMBINE(0, 0, 6) + UNCOMBINE(1, 5, 3) + UNCOMBINE(2, 2, 0) + UNCOMBINE(3, 7, 5) + UNCOMBINE(4, 4, 2) + UNCOMBINE(5, 1, 7) + UNCOMBINE(6, 6, 4) + UNCOMBINE(7, 3, 1) +#undef UNCOMBINE +} + +#ifdef __SSE2__ +#define DECL_X \ + __m128i X0, X1, X2, X3; +#define DECL_Y \ + __m128i Y0, Y1, Y2, Y3; +#define READ_X(in) \ + X0 = (in).q[0]; X1 = (in).q[1]; X2 = (in).q[2]; X3 = (in).q[3]; +#define WRITE_X(out) \ + (out).q[0] = X0; (out).q[1] = X1; (out).q[2] = X2; (out).q[3] = X3; + +#ifdef __XOP__ +#define ARX(out, in1, in2, s) \ + out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); +#else +#define ARX(out, in1, in2, s) { \ + __m128i tmp = _mm_add_epi32(in1, in2); \ + out = _mm_xor_si128(out, _mm_slli_epi32(tmp, s)); \ + out = _mm_xor_si128(out, _mm_srli_epi32(tmp, 32 - s)); \ +} +#endif + +#define SALSA20_2ROUNDS \ + /* Operate on "columns" */ \ + ARX(X1, X0, X3, 7) \ + ARX(X2, X1, X0, 9) \ + ARX(X3, X2, X1, 13) \ + ARX(X0, X3, X2, 18) \ + /* Rearrange data */ \ + X1 = _mm_shuffle_epi32(X1, 0x93); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x39); \ + /* Operate on "rows" */ \ + ARX(X3, X0, X1, 7) \ + ARX(X2, X3, X0, 9) \ + ARX(X1, X2, X3, 13) \ + ARX(X0, X1, X2, 18) \ + /* Rearrange data */ \ + X1 = _mm_shuffle_epi32(X1, 0x39); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x93); + +/** + * Apply the Salsa20 core to the block provided in (X0 ... X3). + */ +#define SALSA20_wrapper(out, rounds) { \ + __m128i Z0 = X0, Z1 = X1, Z2 = X2, Z3 = X3; \ + rounds \ + (out).q[0] = X0 = _mm_add_epi32(X0, Z0); \ + (out).q[1] = X1 = _mm_add_epi32(X1, Z1); \ + (out).q[2] = X2 = _mm_add_epi32(X2, Z2); \ + (out).q[3] = X3 = _mm_add_epi32(X3, Z3); \ +} + +/** + * Apply the Salsa20/2 core to the block provided in X. + */ +#define SALSA20_2(out) \ + SALSA20_wrapper(out, SALSA20_2ROUNDS) + +#define SALSA20_8ROUNDS \ + SALSA20_2ROUNDS SALSA20_2ROUNDS SALSA20_2ROUNDS SALSA20_2ROUNDS + +/** + * Apply the Salsa20/8 core to the block provided in X. + */ +#define SALSA20_8(out) \ + SALSA20_wrapper(out, SALSA20_8ROUNDS) + +#define XOR_X(in) \ + X0 = _mm_xor_si128(X0, (in).q[0]); \ + X1 = _mm_xor_si128(X1, (in).q[1]); \ + X2 = _mm_xor_si128(X2, (in).q[2]); \ + X3 = _mm_xor_si128(X3, (in).q[3]); + +#define XOR_X_2(in1, in2) \ + X0 = _mm_xor_si128((in1).q[0], (in2).q[0]); \ + X1 = _mm_xor_si128((in1).q[1], (in2).q[1]); \ + X2 = _mm_xor_si128((in1).q[2], (in2).q[2]); \ + X3 = _mm_xor_si128((in1).q[3], (in2).q[3]); + +#define XOR_X_WRITE_XOR_Y_2(out, in) \ + (out).q[0] = Y0 = _mm_xor_si128((out).q[0], (in).q[0]); \ + (out).q[1] = Y1 = _mm_xor_si128((out).q[1], (in).q[1]); \ + (out).q[2] = Y2 = _mm_xor_si128((out).q[2], (in).q[2]); \ + (out).q[3] = Y3 = _mm_xor_si128((out).q[3], (in).q[3]); \ + X0 = _mm_xor_si128(X0, Y0); \ + X1 = _mm_xor_si128(X1, Y1); \ + X2 = _mm_xor_si128(X2, Y2); \ + X3 = _mm_xor_si128(X3, Y3); + +#define INTEGERIFY _mm_cvtsi128_si32(X0) + +#else /* !defined(__SSE2__) */ + +#define DECL_X \ + salsa20_blk_t X; +#define DECL_Y \ + salsa20_blk_t Y; + +#define COPY(out, in) \ + (out).d[0] = (in).d[0]; \ + (out).d[1] = (in).d[1]; \ + (out).d[2] = (in).d[2]; \ + (out).d[3] = (in).d[3]; \ + (out).d[4] = (in).d[4]; \ + (out).d[5] = (in).d[5]; \ + (out).d[6] = (in).d[6]; \ + (out).d[7] = (in).d[7]; + +#define READ_X(in) COPY(X, in) +#define WRITE_X(out) COPY(out, X) + +/** + * salsa20(B): + * Apply the Salsa20 core to the provided block. + */ +static inline void salsa20(salsa20_blk_t *restrict B, + salsa20_blk_t *restrict Bout, uint32_t doublerounds) +{ + salsa20_blk_t X; +#define x X.w + + salsa20_simd_unshuffle(B, &X); + + do { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } while (--doublerounds); +#undef x + + { + uint32_t i; + salsa20_simd_shuffle(&X, Bout); + for (i = 0; i < 16; i += 4) { + B->w[i] = Bout->w[i] += B->w[i]; + B->w[i + 1] = Bout->w[i + 1] += B->w[i + 1]; + B->w[i + 2] = Bout->w[i + 2] += B->w[i + 2]; + B->w[i + 3] = Bout->w[i + 3] += B->w[i + 3]; + } + } +} + +/** + * Apply the Salsa20/2 core to the block provided in X. + */ +#define SALSA20_2(out) \ + salsa20(&X, &out, 1); + +/** + * Apply the Salsa20/8 core to the block provided in X. + */ +#define SALSA20_8(out) \ + salsa20(&X, &out, 4); + +#define XOR(out, in1, in2) \ + (out).d[0] = (in1).d[0] ^ (in2).d[0]; \ + (out).d[1] = (in1).d[1] ^ (in2).d[1]; \ + (out).d[2] = (in1).d[2] ^ (in2).d[2]; \ + (out).d[3] = (in1).d[3] ^ (in2).d[3]; \ + (out).d[4] = (in1).d[4] ^ (in2).d[4]; \ + (out).d[5] = (in1).d[5] ^ (in2).d[5]; \ + (out).d[6] = (in1).d[6] ^ (in2).d[6]; \ + (out).d[7] = (in1).d[7] ^ (in2).d[7]; + +#define XOR_X(in) XOR(X, X, in) +#define XOR_X_2(in1, in2) XOR(X, in1, in2) +#define XOR_X_WRITE_XOR_Y_2(out, in) \ + XOR(Y, out, in) \ + COPY(out, Y) \ + XOR(X, X, Y) + +#define INTEGERIFY (uint32_t)X.d[0] +#endif + +/** + * Apply the Salsa20 core to the block provided in X ^ in. + */ +#define SALSA20_XOR_MEM(in, out) \ + XOR_X(in) \ + SALSA20(out) + +#define SALSA20 SALSA20_8 +#else /* pass 2 */ +#undef SALSA20 +#define SALSA20 SALSA20_2 +#endif + +/** + * blockmix_salsa(Bin, Bout): + * Compute Bout = BlockMix_{salsa20, 1}(Bin). The input Bin must be 128 + * bytes in length; the output Bout must also be the same size. + */ +static inline void blockmix_salsa(const salsa20_blk_t *restrict Bin, + salsa20_blk_t *restrict Bout) +{ + DECL_X + + READ_X(Bin[1]) + SALSA20_XOR_MEM(Bin[0], Bout[0]) + SALSA20_XOR_MEM(Bin[1], Bout[1]) +} + +static inline uint32_t blockmix_salsa_xor(const salsa20_blk_t *restrict Bin1, + const salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout) +{ + DECL_X + + XOR_X_2(Bin1[1], Bin2[1]) + XOR_X(Bin1[0]) + SALSA20_XOR_MEM(Bin2[0], Bout[0]) + XOR_X(Bin1[1]) + SALSA20_XOR_MEM(Bin2[1], Bout[1]) + + return INTEGERIFY; +} + +#if _YESPOWER_OPT_C_PASS_ == 1 +/* This is tunable, but it is part of what defines a yespower version */ +/* Version 0.5 */ +#define Swidth_0_5 8 +/* Version 1.0 */ +#define Swidth_1_0 11 + +/* Not tunable in this implementation, hard-coded in a few places */ +#define PWXsimple 2 +#define PWXgather 4 + +/* Derived value. Not tunable on its own. */ +#define PWXbytes (PWXgather * PWXsimple * 8) + +/* (Maybe-)runtime derived values. Not tunable on their own. */ +#define Swidth_to_Sbytes1(Swidth) ((1 << (Swidth)) * PWXsimple * 8) +#define Swidth_to_Smask(Swidth) (((1 << (Swidth)) - 1) * PWXsimple * 8) +#define Smask_to_Smask2(Smask) (((uint64_t)(Smask) << 32) | (Smask)) + +/* These should be compile-time derived */ +#define Smask2_0_5 Smask_to_Smask2(Swidth_to_Smask(Swidth_0_5)) +#define Smask2_1_0 Smask_to_Smask2(Swidth_to_Smask(Swidth_1_0)) + +typedef struct { + uint8_t *S0, *S1, *S2; + size_t w; + uint32_t Sbytes; +} pwxform_ctx_t; + +#define DECL_SMASK2REG /* empty */ +#define MAYBE_MEMORY_BARRIER /* empty */ + +#ifdef __SSE2__ +/* + * (V)PSRLDQ and (V)PSHUFD have higher throughput than (V)PSRLQ on some CPUs + * starting with Sandy Bridge. Additionally, PSHUFD uses separate source and + * destination registers, whereas the shifts would require an extra move + * instruction for our code when building without AVX. Unfortunately, PSHUFD + * is much slower on Conroe (4 cycles latency vs. 1 cycle latency for PSRLQ) + * and somewhat slower on some non-Intel CPUs (luckily not including AMD + * Bulldozer and Piledriver). + */ +#ifdef __AVX__ +#define HI32(X) \ + _mm_srli_si128((X), 4) +#elif 1 /* As an option, check for __SSE4_1__ here not to hurt Conroe */ +#define HI32(X) \ + _mm_shuffle_epi32((X), _MM_SHUFFLE(2,3,0,1)) +#else +#define HI32(X) \ + _mm_srli_epi64((X), 32) +#endif + +#if defined(__x86_64__) && \ + __GNUC__ == 4 && __GNUC_MINOR__ < 6 && !defined(__ICC) +#ifdef __AVX__ +#define MOVQ "vmovq" +#else +/* "movq" would be more correct, but "movd" is supported by older binutils + * due to an error in AMD's spec for x86-64. */ +#define MOVQ "movd" +#endif +#define EXTRACT64(X) ({ \ + uint64_t result; \ + __asm__(MOVQ " %1, %0" : "=r" (result) : "x" (X)); \ + result; \ +}) +#elif defined(__x86_64__) && !defined(_MSC_VER) && !defined(__OPEN64__) +/* MSVC and Open64 had bugs */ +#define EXTRACT64(X) _mm_cvtsi128_si64(X) +#elif defined(__x86_64__) && defined(__SSE4_1__) +/* No known bugs for this intrinsic */ +#include +#define EXTRACT64(X) _mm_extract_epi64((X), 0) +#elif defined(USE_SSE4_FOR_32BIT) && defined(__SSE4_1__) +/* 32-bit */ +#include +#if 0 +/* This is currently unused by the code below, which instead uses these two + * intrinsics explicitly when (!defined(__x86_64__) && defined(__SSE4_1__)) */ +#define EXTRACT64(X) \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ + ((uint64_t)(uint32_t)_mm_extract_epi32((X), 1) << 32)) +#endif +#else +/* 32-bit or compilers with known past bugs in _mm_cvtsi128_si64() */ +#define EXTRACT64(X) \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \ + ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32)) +#endif + +#if defined(__x86_64__) && (defined(__AVX__) || !defined(__GNUC__)) +/* 64-bit with AVX */ +/* Force use of 64-bit AND instead of two 32-bit ANDs */ +#undef DECL_SMASK2REG +#if defined(__GNUC__) && !defined(__ICC) +#define DECL_SMASK2REG uint64_t Smask2reg = Smask2; +/* Force use of lower-numbered registers to reduce number of prefixes, relying + * on out-of-order execution and register renaming. */ +#define FORCE_REGALLOC_1 \ + __asm__("" : "=a" (x), "+d" (Smask2reg), "+S" (S0), "+D" (S1)); +#define FORCE_REGALLOC_2 \ + __asm__("" : : "c" (lo)); +#else +static volatile uint64_t Smask2var = Smask2; +#define DECL_SMASK2REG uint64_t Smask2reg = Smask2var; +#define FORCE_REGALLOC_1 /* empty */ +#define FORCE_REGALLOC_2 /* empty */ +#endif +#define PWXFORM_SIMD(X) { \ + uint64_t x; \ + FORCE_REGALLOC_1 \ + uint32_t lo = x = EXTRACT64(X) & Smask2reg; \ + FORCE_REGALLOC_2 \ + uint32_t hi = x >> 32; \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, *(__m128i *)(S0 + lo)); \ + X = _mm_xor_si128(X, *(__m128i *)(S1 + hi)); \ +} +#elif defined(__x86_64__) +/* 64-bit without AVX. This relies on out-of-order execution and register + * renaming. It may actually be fastest on CPUs with AVX(2) as well - e.g., + * it runs great on Haswell. */ +#warning "Note: using x86-64 inline assembly for pwxform. That's great." +#undef MAYBE_MEMORY_BARRIER +#define MAYBE_MEMORY_BARRIER \ + __asm__("" : : : "memory"); +#ifdef __ILP32__ /* x32 */ +#define REGISTER_PREFIX "e" +#else +#define REGISTER_PREFIX "r" +#endif +#define PWXFORM_SIMD(X) { \ + __m128i H; \ + __asm__( \ + "movd %0, %%rax\n\t" \ + "pshufd $0xb1, %0, %1\n\t" \ + "andq %2, %%rax\n\t" \ + "pmuludq %1, %0\n\t" \ + "movl %%eax, %%ecx\n\t" \ + "shrq $0x20, %%rax\n\t" \ + "paddq (%3,%%" REGISTER_PREFIX "cx), %0\n\t" \ + "pxor (%4,%%" REGISTER_PREFIX "ax), %0\n\t" \ + : "+x" (X), "=x" (H) \ + : "d" (Smask2), "S" (S0), "D" (S1) \ + : "cc", "ax", "cx"); \ +} +#elif defined(USE_SSE4_FOR_32BIT) && defined(__SSE4_1__) +/* 32-bit with SSE4.1 */ +#define PWXFORM_SIMD(X) { \ + __m128i x = _mm_and_si128(X, _mm_set1_epi64x(Smask2)); \ + __m128i s0 = *(__m128i *)(S0 + (uint32_t)_mm_cvtsi128_si32(x)); \ + __m128i s1 = *(__m128i *)(S1 + (uint32_t)_mm_extract_epi32(x, 1)); \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, s0); \ + X = _mm_xor_si128(X, s1); \ +} +#else +/* 32-bit without SSE4.1 */ +#define PWXFORM_SIMD(X) { \ + uint64_t x = EXTRACT64(X) & Smask2; \ + __m128i s0 = *(__m128i *)(S0 + (uint32_t)x); \ + __m128i s1 = *(__m128i *)(S1 + (x >> 32)); \ + X = _mm_mul_epu32(HI32(X), X); \ + X = _mm_add_epi64(X, s0); \ + X = _mm_xor_si128(X, s1); \ +} +#endif + +#define PWXFORM_SIMD_WRITE(X, Sw) \ + PWXFORM_SIMD(X) \ + MAYBE_MEMORY_BARRIER \ + *(__m128i *)(Sw + w) = X; \ + MAYBE_MEMORY_BARRIER + +#define PWXFORM_ROUND \ + PWXFORM_SIMD(X0) \ + PWXFORM_SIMD(X1) \ + PWXFORM_SIMD(X2) \ + PWXFORM_SIMD(X3) + +#define PWXFORM_ROUND_WRITE4 \ + PWXFORM_SIMD_WRITE(X0, S0) \ + PWXFORM_SIMD_WRITE(X1, S1) \ + w += 16; \ + PWXFORM_SIMD_WRITE(X2, S0) \ + PWXFORM_SIMD_WRITE(X3, S1) \ + w += 16; + +#define PWXFORM_ROUND_WRITE2 \ + PWXFORM_SIMD_WRITE(X0, S0) \ + PWXFORM_SIMD_WRITE(X1, S1) \ + w += 16; \ + PWXFORM_SIMD(X2) \ + PWXFORM_SIMD(X3) + +#else /* !defined(__SSE2__) */ + +#define PWXFORM_SIMD(x0, x1) { \ + uint64_t x = x0 & Smask2; \ + uint64_t *p0 = (uint64_t *)(S0 + (uint32_t)x); \ + uint64_t *p1 = (uint64_t *)(S1 + (x >> 32)); \ + x0 = ((x0 >> 32) * (uint32_t)x0 + p0[0]) ^ p1[0]; \ + x1 = ((x1 >> 32) * (uint32_t)x1 + p0[1]) ^ p1[1]; \ +} + +#define PWXFORM_SIMD_WRITE(x0, x1, Sw) \ + PWXFORM_SIMD(x0, x1) \ + ((uint64_t *)(Sw + w))[0] = x0; \ + ((uint64_t *)(Sw + w))[1] = x1; + +#define PWXFORM_ROUND \ + PWXFORM_SIMD(X.d[0], X.d[1]) \ + PWXFORM_SIMD(X.d[2], X.d[3]) \ + PWXFORM_SIMD(X.d[4], X.d[5]) \ + PWXFORM_SIMD(X.d[6], X.d[7]) + +#define PWXFORM_ROUND_WRITE4 \ + PWXFORM_SIMD_WRITE(X.d[0], X.d[1], S0) \ + PWXFORM_SIMD_WRITE(X.d[2], X.d[3], S1) \ + w += 16; \ + PWXFORM_SIMD_WRITE(X.d[4], X.d[5], S0) \ + PWXFORM_SIMD_WRITE(X.d[6], X.d[7], S1) \ + w += 16; + +#define PWXFORM_ROUND_WRITE2 \ + PWXFORM_SIMD_WRITE(X.d[0], X.d[1], S0) \ + PWXFORM_SIMD_WRITE(X.d[2], X.d[3], S1) \ + w += 16; \ + PWXFORM_SIMD(X.d[4], X.d[5]) \ + PWXFORM_SIMD(X.d[6], X.d[7]) +#endif + +#define PWXFORM \ + PWXFORM_ROUND PWXFORM_ROUND PWXFORM_ROUND \ + PWXFORM_ROUND PWXFORM_ROUND PWXFORM_ROUND + +#define Smask2 Smask2_0_5 + +#else /* pass 2 */ + +#undef PWXFORM +#define PWXFORM \ + PWXFORM_ROUND_WRITE4 PWXFORM_ROUND_WRITE2 PWXFORM_ROUND_WRITE2 \ + w &= Smask2; \ + { \ + uint8_t *Stmp = S2; \ + S2 = S1; \ + S1 = S0; \ + S0 = Stmp; \ + } + +#undef Smask2 +#define Smask2 Smask2_1_0 + +#endif + +/** + * blockmix_pwxform(Bin, Bout, r, S): + * Compute Bout = BlockMix_pwxform{salsa20, r, S}(Bin). The input Bin must + * be 128r bytes in length; the output Bout must also be the same size. + */ +static void blockmix(const salsa20_blk_t *restrict Bin, + salsa20_blk_t *restrict Bout, size_t r, pwxform_ctx_t *restrict ctx) +{ + if (unlikely(!ctx)) { + blockmix_salsa(Bin, Bout); + return; + } + + uint8_t *S0 = ctx->S0, *S1 = ctx->S1; +#if _YESPOWER_OPT_C_PASS_ > 1 + uint8_t *S2 = ctx->S2; + size_t w = ctx->w; +#endif + size_t i; + DECL_X + + /* Convert count of 128-byte blocks to max index of 64-byte block */ + r = r * 2 - 1; + + READ_X(Bin[r]) + + DECL_SMASK2REG + + i = 0; + do { + XOR_X(Bin[i]) + PWXFORM + if (unlikely(i >= r)) + break; + WRITE_X(Bout[i]) + i++; + } while (1); + +#if _YESPOWER_OPT_C_PASS_ > 1 + ctx->S0 = S0; ctx->S1 = S1; ctx->S2 = S2; + ctx->w = w; +#endif + + SALSA20(Bout[i]) +} + +static uint32_t blockmix_xor(const salsa20_blk_t *restrict Bin1, + const salsa20_blk_t *restrict Bin2, salsa20_blk_t *restrict Bout, + size_t r, pwxform_ctx_t *restrict ctx) +{ + if (unlikely(!ctx)) + return blockmix_salsa_xor(Bin1, Bin2, Bout); + + uint8_t *S0 = ctx->S0, *S1 = ctx->S1; +#if _YESPOWER_OPT_C_PASS_ > 1 + uint8_t *S2 = ctx->S2; + size_t w = ctx->w; +#endif + size_t i; + DECL_X + + /* Convert count of 128-byte blocks to max index of 64-byte block */ + r = r * 2 - 1; + +#ifdef PREFETCH + PREFETCH(&Bin2[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i], _MM_HINT_T0) + } +#endif + + XOR_X_2(Bin1[r], Bin2[r]) + + DECL_SMASK2REG + + i = 0; + r--; + do { + XOR_X(Bin1[i]) + XOR_X(Bin2[i]) + PWXFORM + WRITE_X(Bout[i]) + + XOR_X(Bin1[i + 1]) + XOR_X(Bin2[i + 1]) + PWXFORM + + if (unlikely(i >= r)) + break; + + WRITE_X(Bout[i + 1]) + + i += 2; + } while (1); + i++; + +#if _YESPOWER_OPT_C_PASS_ > 1 + ctx->S0 = S0; ctx->S1 = S1; ctx->S2 = S2; + ctx->w = w; +#endif + + SALSA20(Bout[i]) + + return INTEGERIFY; +} + +static uint32_t blockmix_xor_save(salsa20_blk_t *restrict Bin1out, + salsa20_blk_t *restrict Bin2, + size_t r, pwxform_ctx_t *restrict ctx) +{ + uint8_t *S0 = ctx->S0, *S1 = ctx->S1; +#if _YESPOWER_OPT_C_PASS_ > 1 + uint8_t *S2 = ctx->S2; + size_t w = ctx->w; +#endif + size_t i; + DECL_X + DECL_Y + + /* Convert count of 128-byte blocks to max index of 64-byte block */ + r = r * 2 - 1; + +#ifdef PREFETCH + PREFETCH(&Bin2[r], _MM_HINT_T0) + for (i = 0; i < r; i++) { + PREFETCH(&Bin2[i], _MM_HINT_T0) + } +#endif + + XOR_X_2(Bin1out[r], Bin2[r]) + + DECL_SMASK2REG + + i = 0; + r--; + do { + XOR_X_WRITE_XOR_Y_2(Bin2[i], Bin1out[i]) + PWXFORM + WRITE_X(Bin1out[i]) + + XOR_X_WRITE_XOR_Y_2(Bin2[i + 1], Bin1out[i + 1]) + PWXFORM + + if (unlikely(i >= r)) + break; + + WRITE_X(Bin1out[i + 1]) + + i += 2; + } while (1); + i++; + +#if _YESPOWER_OPT_C_PASS_ > 1 + ctx->S0 = S0; ctx->S1 = S1; ctx->S2 = S2; + ctx->w = w; +#endif + + SALSA20(Bin1out[i]) + + return INTEGERIFY; +} + +#if _YESPOWER_OPT_C_PASS_ == 1 +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint32_t integerify(const salsa20_blk_t *B, size_t r) +{ +/* + * Our 64-bit words are in host byte order, which is why we don't just read + * w[0] here (would be wrong on big-endian). Also, our 32-bit words are + * SIMD-shuffled, but we only care about the least significant 32 bits anyway. + */ + return (uint32_t)B[2 * r - 1].d[0]; +} +#endif + +/** + * smix1(B, r, N, V, XY, S): + * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 128r+64 bytes in length. N must be even and at least 4. + * The array V must be aligned to a multiple of 64 bytes, and arrays B and XY + * to a multiple of at least 16 bytes. + */ +static void smix1(uint8_t *B, size_t r, uint32_t N, + salsa20_blk_t *V, salsa20_blk_t *XY, pwxform_ctx_t *ctx) +{ + size_t s = 2 * r; + salsa20_blk_t *X = V, *Y = &V[s], *V_j; + uint32_t i, j, n; + +#if _YESPOWER_OPT_C_PASS_ == 1 + for (i = 0; i < 2 * r; i++) { +#else + for (i = 0; i < 2; i++) { +#endif + const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64]; + salsa20_blk_t *tmp = Y; + salsa20_blk_t *dst = &X[i]; + size_t k; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + +#if _YESPOWER_OPT_C_PASS_ > 1 + for (i = 1; i < r; i++) + blockmix(&X[(i - 1) * 2], &X[i * 2], 1, ctx); +#endif + + blockmix(X, Y, r, ctx); + X = Y + s; + blockmix(Y, X, r, ctx); + j = integerify(X, r); + + for (n = 2; n < N; n <<= 1) { + uint32_t m = (n < N / 2) ? n : (N - 1 - n); + for (i = 1; i < m; i += 2) { + Y = X + s; + j &= n - 1; + j += i - 1; + V_j = &V[j * s]; + j = blockmix_xor(X, V_j, Y, r, ctx); + j &= n - 1; + j += i; + V_j = &V[j * s]; + X = Y + s; + j = blockmix_xor(Y, V_j, X, r, ctx); + } + } + n >>= 1; + + j &= n - 1; + j += N - 2 - n; + V_j = &V[j * s]; + Y = X + s; + j = blockmix_xor(X, V_j, Y, r, ctx); + j &= n - 1; + j += N - 1 - n; + V_j = &V[j * s]; + blockmix_xor(Y, V_j, XY, r, ctx); + + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = &XY[i]; + salsa20_blk_t *tmp = &XY[s]; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64]; + size_t k; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * smix2(B, r, N, Nloop, V, XY, S): + * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r bytes in length. N must be a power of 2 and at + * least 2. Nloop must be even. The array V must be aligned to a multiple of + * 64 bytes, and arrays B and XY to a multiple of at least 16 bytes. + */ +static void smix2(uint8_t *B, size_t r, uint32_t N, uint32_t Nloop, + salsa20_blk_t *V, salsa20_blk_t *XY, pwxform_ctx_t *ctx) +{ + size_t s = 2 * r; + salsa20_blk_t *X = XY, *Y = &XY[s]; + uint32_t i, j; + + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64]; + salsa20_blk_t *tmp = Y; + salsa20_blk_t *dst = &X[i]; + size_t k; + for (k = 0; k < 16; k++) + tmp->w[k] = le32dec(&src->w[k]); + salsa20_simd_shuffle(tmp, dst); + } + + j = integerify(X, r) & (N - 1); + +#if _YESPOWER_OPT_C_PASS_ == 1 + if (Nloop > 2) { +#endif + do { + salsa20_blk_t *V_j = &V[j * s]; + j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1); + V_j = &V[j * s]; + j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1); + } while (Nloop -= 2); +#if _YESPOWER_OPT_C_PASS_ == 1 + } else { + const salsa20_blk_t * V_j = &V[j * s]; + j = blockmix_xor(X, V_j, Y, r, ctx) & (N - 1); + V_j = &V[j * s]; + blockmix_xor(Y, V_j, X, r, ctx); + } +#endif + + for (i = 0; i < 2 * r; i++) { + const salsa20_blk_t *src = &X[i]; + salsa20_blk_t *tmp = Y; + salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64]; + size_t k; + for (k = 0; k < 16; k++) + le32enc(&tmp->w[k], src->w[k]); + salsa20_simd_unshuffle(tmp, dst); + } +} + +/** + * smix(B, r, N, V, XY, S): + * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * XY must be 256r bytes in length. N must be a power of 2 and at least 16. + * The array V must be aligned to a multiple of 64 bytes, and arrays B and XY + * to a multiple of at least 16 bytes (aligning them to 64 bytes as well saves + * cache lines, but it might also result in cache bank conflicts). + */ +static void smix(uint8_t *B, size_t r, uint32_t N, + salsa20_blk_t *V, salsa20_blk_t *XY, pwxform_ctx_t *ctx) +{ +#if _YESPOWER_OPT_C_PASS_ == 1 + uint32_t Nloop_all = (N + 2) / 3; /* 1/3, round up */ + uint32_t Nloop_rw = Nloop_all; + + Nloop_all++; Nloop_all &= ~(uint32_t)1; /* round up to even */ + Nloop_rw &= ~(uint32_t)1; /* round down to even */ +#else + uint32_t Nloop_rw = (N + 2) / 3; /* 1/3, round up */ + Nloop_rw++; Nloop_rw &= ~(uint32_t)1; /* round up to even */ +#endif + + smix1(B, 1, ctx->Sbytes / 128, (salsa20_blk_t *)ctx->S0, XY, NULL); + smix1(B, r, N, V, XY, ctx); + smix2(B, r, N, Nloop_rw /* must be > 2 */, V, XY, ctx); +#if _YESPOWER_OPT_C_PASS_ == 1 + if (Nloop_all > Nloop_rw) + smix2(B, r, N, 2, V, XY, ctx); +#endif +} + +#if _YESPOWER_OPT_C_PASS_ == 1 +#undef _YESPOWER_OPT_C_PASS_ +#define _YESPOWER_OPT_C_PASS_ 2 +#define blockmix_salsa blockmix_salsa_1_0 +#define blockmix_salsa_xor blockmix_salsa_xor_1_0 +#define blockmix blockmix_1_0 +#define blockmix_xor blockmix_xor_1_0 +#define blockmix_xor_save blockmix_xor_save_1_0 +#define smix1 smix1_1_0 +#define smix2 smix2_1_0 +#define smix smix_1_0 +#include "yespower-blake2b.c" +#undef smix + +/** + * yespower(local, src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * local is the thread-local data structure, allowing to preserve and reuse a + * memory allocation across calls, thereby reducing its overhead. + * + * Return 0 on success; or -1 on error. + */ +int yespower_b2b(yespower_local_t *local, + const uint8_t *src, size_t srclen, + const yespower_params_t *params, + yespower_binary_t *dst) +{ + uint32_t N = params->N; + uint32_t r = params->r; + const uint8_t *pers = params->pers; + size_t perslen = params->perslen; + uint32_t Swidth; + size_t B_size, V_size, XY_size, need; + uint8_t *B, *S; + salsa20_blk_t *V, *XY; + pwxform_ctx_t ctx; + uint8_t init_hash[32]; + + /* Sanity-check parameters */ + if ((N < 1024 || N > 512 * 1024 || r < 8 || r > 32 || + (N & (N - 1)) != 0 || + (!pers && perslen))) { + errno = EINVAL; + goto fail; + } + + /* Allocate memory */ + B_size = (size_t)128 * r; + V_size = B_size * N; + + XY_size = B_size + 64; + Swidth = Swidth_1_0; + ctx.Sbytes = 3 * Swidth_to_Sbytes1(Swidth); + + need = B_size + V_size + XY_size + ctx.Sbytes; + if (local->aligned_size < need) { + if (free_region(local)) + goto fail; + if (!alloc_region(local, need)) + goto fail; + } + B = (uint8_t *)local->aligned; + V = (salsa20_blk_t *)((uint8_t *)B + B_size); + XY = (salsa20_blk_t *)((uint8_t *)V + V_size); + S = (uint8_t *)XY + XY_size; + ctx.S0 = S; + ctx.S1 = S + Swidth_to_Sbytes1(Swidth); + + blake2b_yp_hash(init_hash, src, srclen); + + ctx.S2 = S + 2 * Swidth_to_Sbytes1(Swidth); + ctx.w = 0; + + if (pers) { + src = pers; + srclen = perslen; + } else { + srclen = 0; + } + + pbkdf2_blake2b_yp(init_hash, sizeof(init_hash), src, srclen, 1, B, 128); + memcpy(init_hash, B, sizeof(init_hash)); + smix_1_0(B, r, N, V, XY, &ctx); + hmac_blake2b_yp_hash((uint8_t *)dst, B + B_size - 64, 64, init_hash, sizeof(init_hash)); + + /* Success! */ + return 0; + +fail: + memset(dst, 0xff, sizeof(*dst)); + return -1; +} + +/** + * yespower_tls(src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * The memory allocation is maintained internally using thread-local storage. + * + * Return 0 on success; or -1 on error. + */ +int yespower_b2b_tls(const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst) +{ + static __thread int initialized = 0; + static __thread yespower_local_t local; + + if (!initialized) { + init_region(&local); + initialized = 1; + } + + return yespower_b2b(&local, src, srclen, params, dst); +} + +#endif \ No newline at end of file diff --git a/src/Native/libmultihash/yespower/yespower-combined.c b/src/Native/libmultihash/yespower/yespower-combined.c new file mode 100644 index 000000000..f4535cfe0 --- /dev/null +++ b/src/Native/libmultihash/yespower/yespower-combined.c @@ -0,0 +1,1314 @@ +#include +#include +#include +#include +#include + +#include "sha256.h" +#include "sysendian.h" +#include "yespower.h" +#include "insecure_memzero.h" + +#ifdef __ICC +/* Miscompile with icc 14.0.0 (at least), so don't use restrict there */ +#define restrict +#elif __STDC_VERSION__ >= 199901L +/* Have restrict */ +#elif defined(__GNUC__) +#define restrict __restrict +#else +#define restrict +#endif + +/* + * Encode a length len*2 vector of (uint32_t) into a length len*8 vector of + * (uint8_t) in big-endian form. + */ +static void +be32enc_vect(uint8_t * dst, const uint32_t * src, size_t len) +{ + + /* Encode vector, two words at a time. */ + do { + be32enc(&dst[0], src[0]); + be32enc(&dst[4], src[1]); + src += 2; + dst += 8; + } while (--len); +} + +/* + * Decode a big-endian length len*8 vector of (uint8_t) into a length + * len*2 vector of (uint32_t). + */ +static void +be32dec_vect(uint32_t * dst, const uint8_t * src, size_t len) +{ + + /* Decode vector, two words at a time. */ + do { + dst[0] = be32dec(&src[0]); + dst[1] = be32dec(&src[4]); + src += 8; + dst += 2; + } while (--len); +} + +/* SHA256 round constants. */ +static const uint32_t Krnd[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +/* SHA256 round function */ +#define RND(a, b, c, d, e, f, g, h, k) \ + h += S1(e) + Ch(e, f, g) + k; \ + d += h; \ + h += S0(a) + Maj(a, b, c); + +/* Adjusted round function for rotating state */ +#define RNDr(S, W, i, ii) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i + ii] + Krnd[i + ii]) + +/* Message schedule computation */ +#define MSCH(W, ii, i) \ + W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii] + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void +SHA256_Transform(uint32_t state[static restrict 8], + const uint8_t block[static restrict 64], + uint32_t W[static restrict 64], uint32_t S[static restrict 8]) +{ + int i; + + /* 1. Prepare the first part of the message schedule W. */ + be32dec_vect(W, block, 8); + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + for (i = 0; i < 64; i += 16) { + RNDr(S, W, 0, i); + RNDr(S, W, 1, i); + RNDr(S, W, 2, i); + RNDr(S, W, 3, i); + RNDr(S, W, 4, i); + RNDr(S, W, 5, i); + RNDr(S, W, 6, i); + RNDr(S, W, 7, i); + RNDr(S, W, 8, i); + RNDr(S, W, 9, i); + RNDr(S, W, 10, i); + RNDr(S, W, 11, i); + RNDr(S, W, 12, i); + RNDr(S, W, 13, i); + RNDr(S, W, 14, i); + RNDr(S, W, 15, i); + + if (i == 48) + break; + MSCH(W, 0, i); + MSCH(W, 1, i); + MSCH(W, 2, i); + MSCH(W, 3, i); + MSCH(W, 4, i); + MSCH(W, 5, i); + MSCH(W, 6, i); + MSCH(W, 7, i); + MSCH(W, 8, i); + MSCH(W, 9, i); + MSCH(W, 10, i); + MSCH(W, 11, i); + MSCH(W, 12, i); + MSCH(W, 13, i); + MSCH(W, 14, i); + MSCH(W, 15, i); + } + + /* 4. Mix local working variables into global state. */ + state[0] += S[0]; + state[1] += S[1]; + state[2] += S[2]; + state[3] += S[3]; + state[4] += S[4]; + state[5] += S[5]; + state[6] += S[6]; + state[7] += S[7]; +} + +static const uint8_t PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* Add padding and terminating bit-count. */ +static void +SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[static restrict 72]) +{ + size_t r; + + /* Figure out how many bytes we have buffered. */ + r = (ctx->count >> 3) & 0x3f; + + /* Pad to 56 mod 64, transforming if we finish a block en route. */ + if (r < 56) { + /* Pad to 56 mod 64. */ + memcpy(&ctx->buf[r], PAD, 56 - r); + } else { + /* Finish the current block and mix. */ + memcpy(&ctx->buf[r], PAD, 64 - r); + SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); + + /* The start of the final block is all zeroes. */ + memset(&ctx->buf[0], 0, 56); + } + + /* Add the terminating bit-count. */ + be64enc(&ctx->buf[56], ctx->count); + + /* Mix in the final block. */ + SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); +} + +/* Magic initialization constants. */ +static const uint32_t initial_state[8] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +/** + * SHA256_Init(ctx): + * Initialize the SHA256 context ${ctx}. + */ +void +SHA256_Init(SHA256_CTX * ctx) +{ + + /* Zero bits processed so far. */ + ctx->count = 0; + + /* Initialize state. */ + memcpy(ctx->state, initial_state, sizeof(initial_state)); +} + +/** + * SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. + */ +static void +_SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len, + uint32_t tmp32[static restrict 72]) +{ + uint32_t r; + const uint8_t * src = in; + + /* Return immediately if we have nothing to do. */ + if (len == 0) + return; + + /* Number of bytes left in the buffer from previous updates. */ + r = (ctx->count >> 3) & 0x3f; + + /* Update number of bits. */ + ctx->count += (uint64_t)(len) << 3; + + /* Handle the case where we don't need to perform any transforms. */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], src, len); + return; + } + + /* Finish the current block. */ + memcpy(&ctx->buf[r], src, 64 - r); + SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks. */ + while (len >= 64) { + SHA256_Transform(ctx->state, src, &tmp32[0], &tmp32[64]); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer. */ + memcpy(ctx->buf, src, len); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len) +{ + uint32_t tmp32[72]; + + /* Call the real function. */ + _SHA256_Update(ctx, in, len, tmp32); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); +} + +/** + * SHA256_Final(digest, ctx): + * Output the SHA256 hash of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +static void +_SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx, + uint32_t tmp32[static restrict 72]) +{ + + /* Add padding. */ + SHA256_Pad(ctx, tmp32); + + /* Write the hash. */ + be32enc_vect(digest, ctx->state, 4); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx) +{ + uint32_t tmp32[72]; + + /* Call the real function. */ + _SHA256_Final(digest, ctx, tmp32); + + /* Clear the context state. */ + insecure_memzero(ctx, sizeof(SHA256_CTX)); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); +} + +/** + * SHA256_Buf(in, len, digest): + * Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}. + */ +void +SHA256_Buf(const void * in, size_t len, uint8_t digest[32]) +{ + SHA256_CTX ctx; + uint32_t tmp32[72]; + + SHA256_Init(&ctx); + _SHA256_Update(&ctx, in, len, tmp32); + _SHA256_Final(digest, &ctx, tmp32); + + /* Clean the stack. */ + insecure_memzero(&ctx, sizeof(SHA256_CTX)); + insecure_memzero(tmp32, 288); +} + +/** + * HMAC_SHA256_Init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +static void +_HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen, + uint32_t tmp32[static restrict 72], uint8_t pad[static restrict 64], + uint8_t khash[static restrict 32]) +{ + const uint8_t * K = _K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + SHA256_Init(&ctx->ictx); + _SHA256_Update(&ctx->ictx, K, Klen, tmp32); + _SHA256_Final(khash, &ctx->ictx, tmp32); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + SHA256_Init(&ctx->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + _SHA256_Update(&ctx->ictx, pad, 64, tmp32); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + SHA256_Init(&ctx->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + _SHA256_Update(&ctx->octx, pad, 64, tmp32); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + uint32_t tmp32[72]; + uint8_t pad[64]; + uint8_t khash[32]; + + /* Call the real function. */ + _HMAC_SHA256_Init(ctx, _K, Klen, tmp32, pad, khash); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); + insecure_memzero(khash, 32); + insecure_memzero(pad, 64); +} + +/** + * HMAC_SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +static void +_HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len, + uint32_t tmp32[static restrict 72]) +{ + + /* Feed data to the inner SHA256 operation. */ + _SHA256_Update(&ctx->ictx, in, len, tmp32); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len) +{ + uint32_t tmp32[72]; + + /* Call the real function. */ + _HMAC_SHA256_Update(ctx, in, len, tmp32); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); +} + +/** + * HMAC_SHA256_Final(digest, ctx): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +static void +_HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx, + uint32_t tmp32[static restrict 72], uint8_t ihash[static restrict 32]) +{ + + /* Finish the inner SHA256 operation. */ + _SHA256_Final(ihash, &ctx->ictx, tmp32); + + /* Feed the inner hash to the outer SHA256 operation. */ + _SHA256_Update(&ctx->octx, ihash, 32, tmp32); + + /* Finish the outer SHA256 operation. */ + _SHA256_Final(digest, &ctx->octx, tmp32); +} + +/* Wrapper function for intermediate-values sanitization. */ +void +HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx) +{ + uint32_t tmp32[72]; + uint8_t ihash[32]; + + /* Call the real function. */ + _HMAC_SHA256_Final(digest, ctx, tmp32, ihash); + + /* Clean the stack. */ + insecure_memzero(tmp32, 288); + insecure_memzero(ihash, 32); +} + +/** + * HMAC_SHA256_Buf(K, Klen, in, len, digest): + * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of + * length ${Klen}, and write the result to ${digest}. + */ +void +HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len, + uint8_t digest[32]) +{ + HMAC_SHA256_CTX ctx; + uint32_t tmp32[72]; + uint8_t tmp8[96]; + + _HMAC_SHA256_Init(&ctx, K, Klen, tmp32, &tmp8[0], &tmp8[64]); + _HMAC_SHA256_Update(&ctx, in, len, tmp32); + _HMAC_SHA256_Final(digest, &ctx, tmp32, &tmp8[0]); + + /* Clean the stack. */ + insecure_memzero(&ctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(tmp32, 288); + insecure_memzero(tmp8, 96); +} + +/* Add padding and terminating bit-count, but don't invoke Transform yet. */ +static int +SHA256_Pad_Almost(SHA256_CTX * ctx, uint8_t len[static restrict 8], + uint32_t tmp32[static restrict 72]) +{ + uint32_t r; + + r = (ctx->count >> 3) & 0x3f; + if (r >= 56) + return -1; + + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + be64enc(len, ctx->count); + + /* Add 1--56 bytes so that the resulting length is 56 mod 64. */ + _SHA256_Update(ctx, PAD, 56 - r, tmp32); + + /* Add the terminating bit-count. */ + ctx->buf[63] = len[7]; + _SHA256_Update(ctx, len, 7, tmp32); + + return 0; +} + +/** + * PBKDF2_SHA256_YP(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256_YP(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX Phctx, PShctx, hctx; + uint32_t tmp32[72]; + union { + uint8_t tmp8[96]; + uint32_t state[8]; + } u; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Sanity-check. */ + assert(dkLen <= 32 * (size_t)(UINT32_MAX)); + + if (c == 1 && (dkLen & 31) == 0 && (saltlen & 63) <= 51) { + uint32_t oldcount; + uint8_t * ivecp; + + /* Compute HMAC state after processing P and S. */ + _HMAC_SHA256_Init(&hctx, passwd, passwdlen, + tmp32, &u.tmp8[0], &u.tmp8[64]); + _HMAC_SHA256_Update(&hctx, salt, saltlen, tmp32); + + /* Prepare ictx padding. */ + oldcount = hctx.ictx.count & (0x3f << 3); + _HMAC_SHA256_Update(&hctx, "\0\0\0", 4, tmp32); + if ((hctx.ictx.count & (0x3f << 3)) < oldcount || + SHA256_Pad_Almost(&hctx.ictx, u.tmp8, tmp32)) + goto generic; /* Can't happen due to saltlen check */ + ivecp = hctx.ictx.buf + (oldcount >> 3); + + /* Prepare octx padding. */ + hctx.octx.count += 32 << 3; + SHA256_Pad_Almost(&hctx.octx, u.tmp8, tmp32); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivecp, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(u.state, hctx.ictx.state, sizeof(u.state)); + SHA256_Transform(u.state, hctx.ictx.buf, + &tmp32[0], &tmp32[64]); + be32enc_vect(hctx.octx.buf, u.state, 4); + memcpy(u.state, hctx.octx.state, sizeof(u.state)); + SHA256_Transform(u.state, hctx.octx.buf, + &tmp32[0], &tmp32[64]); + be32enc_vect(&buf[i * 32], u.state, 4); + } + + goto cleanup; + } + +generic: + /* Compute HMAC state after processing P. */ + _HMAC_SHA256_Init(&Phctx, passwd, passwdlen, + tmp32, &u.tmp8[0], &u.tmp8[64]); + + /* Compute HMAC state after processing P and S. */ + memcpy(&PShctx, &Phctx, sizeof(HMAC_SHA256_CTX)); + _HMAC_SHA256_Update(&PShctx, salt, saltlen, tmp32); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + be32enc(ivec, (uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + _HMAC_SHA256_Update(&hctx, ivec, 4, tmp32); + _HMAC_SHA256_Final(T, &hctx, tmp32, u.tmp8); + + if (c > 1) { + /* T_i = U_1 ... */ + memcpy(U, T, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + memcpy(&hctx, &Phctx, sizeof(HMAC_SHA256_CTX)); + _HMAC_SHA256_Update(&hctx, U, 32, tmp32); + _HMAC_SHA256_Final(U, &hctx, tmp32, u.tmp8); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean the stack. */ + insecure_memzero(&Phctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(U, 32); + insecure_memzero(T, 32); + +cleanup: + insecure_memzero(&hctx, sizeof(HMAC_SHA256_CTX)); + insecure_memzero(tmp32, 288); + insecure_memzero(&u, sizeof(u)); +} + +static void blkcpy(uint32_t *dst, const uint32_t *src, size_t count) +{ + do { + *dst++ = *src++; + } while (--count); +} + +static void blkxor(uint32_t *dst, const uint32_t *src, size_t count) +{ + do { + *dst++ ^= *src++; + } while (--count); +} + +/** + * salsa20(B): + * Apply the Salsa20 core to the provided block. + */ +static void salsa20(uint32_t B[16], uint32_t rounds) +{ + uint32_t x[16]; + size_t i; + + /* SIMD unshuffle */ + for (i = 0; i < 16; i++) + x[i * 5 % 16] = B[i]; + + for (i = 0; i < rounds; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + + /* SIMD shuffle */ + for (i = 0; i < 16; i++) + B[i] += x[i * 5 % 16]; +} + +/** + * blockmix_salsa(B): + * Compute B = BlockMix_{salsa20, 1}(B). The input B must be 128 bytes in + * length. + */ +static void blockmix_salsa(uint32_t *B, uint32_t rounds) +{ + uint32_t X[16]; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &B[16], 16); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2; i++) { + /* 3: X <-- H(X xor B_i) */ + blkxor(X, &B[i * 16], 16); + salsa20(X, rounds); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&B[i * 16], X, 16); + } +} + +/* + * These are tunable, but they must meet certain constraints and are part of + * what defines a yespower version. + */ +#define PWXsimple 2 +#define PWXgather 4 +/* Version 0.5 */ +#define PWXrounds_0_5 6 +#define Swidth_0_5 8 +/* Version 1.0 */ +#define PWXrounds_1_0 3 +#define Swidth_1_0 11 + +/* Derived values. Not tunable on their own. */ +#define PWXbytes (PWXgather * PWXsimple * 8) +#define PWXwords (PWXbytes / sizeof(uint32_t)) +#define rmin ((PWXbytes + 127) / 128) + +/* Runtime derived values. Not tunable on their own. */ +#define Swidth_to_Sbytes1(Swidth) ((1 << Swidth) * PWXsimple * 8) +#define Swidth_to_Smask(Swidth) (((1 << Swidth) - 1) * PWXsimple * 8) + +typedef struct { + yespower_version_t version; + uint32_t salsa20_rounds; + uint32_t PWXrounds, Swidth, Sbytes, Smask; + uint32_t *S; + uint32_t (*S0)[2], (*S1)[2], (*S2)[2]; + size_t w; +} pwxform_ctx_t; + +/** + * pwxform(B): + * Transform the provided block using the provided S-boxes. + */ +static void pwxform(uint32_t *B, pwxform_ctx_t *ctx) +{ + uint32_t (*X)[PWXsimple][2] = (uint32_t (*)[PWXsimple][2])B; + uint32_t (*S0)[2] = ctx->S0, (*S1)[2] = ctx->S1, (*S2)[2] = ctx->S2; + uint32_t Smask = ctx->Smask; + size_t w = ctx->w; + size_t i, j, k; + + /* 1: for i = 0 to PWXrounds - 1 do */ + for (i = 0; i < ctx->PWXrounds; i++) { + /* 2: for j = 0 to PWXgather - 1 do */ + for (j = 0; j < PWXgather; j++) { + uint32_t xl = X[j][0][0]; + uint32_t xh = X[j][0][1]; + uint32_t (*p0)[2], (*p1)[2]; + + /* 3: p0 <-- (lo(B_{j,0}) & Smask) / (PWXsimple * 8) */ + p0 = S0 + (xl & Smask) / sizeof(*S0); + /* 4: p1 <-- (hi(B_{j,0}) & Smask) / (PWXsimple * 8) */ + p1 = S1 + (xh & Smask) / sizeof(*S1); + + /* 5: for k = 0 to PWXsimple - 1 do */ + for (k = 0; k < PWXsimple; k++) { + uint64_t x, s0, s1; + + /* 6: B_{j,k} <-- (hi(B_{j,k}) * lo(B_{j,k}) + S0_{p0,k}) xor S1_{p1,k} */ + s0 = ((uint64_t)p0[k][1] << 32) + p0[k][0]; + s1 = ((uint64_t)p1[k][1] << 32) + p1[k][0]; + + xl = X[j][k][0]; + xh = X[j][k][1]; + + x = (uint64_t)xh * xl; + x += s0; + x ^= s1; + + X[j][k][0] = x; + X[j][k][1] = x >> 32; + } + + if (ctx->version != YESPOWER_0_5 && + (i == 0 || j < PWXgather / 2)) { + if (j & 1) { + for (k = 0; k < PWXsimple; k++) { + S1[w][0] = X[j][k][0]; + S1[w][1] = X[j][k][1]; + w++; + } + } else { + for (k = 0; k < PWXsimple; k++) { + S0[w + k][0] = X[j][k][0]; + S0[w + k][1] = X[j][k][1]; + } + } + } + } + } + + if (ctx->version != YESPOWER_0_5) { + /* 14: (S0, S1, S2) <-- (S2, S0, S1) */ + ctx->S0 = S2; + ctx->S1 = S0; + ctx->S2 = S1; + /* 15: w <-- w mod 2^Swidth */ + ctx->w = w & ((1 << ctx->Swidth) * PWXsimple - 1); + } +} + +/** + * blockmix_pwxform(B, ctx, r): + * Compute B = BlockMix_pwxform{salsa20, ctx, r}(B). The input B must be + * 128r bytes in length. + */ +static void blockmix_pwxform(uint32_t *B, pwxform_ctx_t *ctx, size_t r) +{ + uint32_t X[PWXwords]; + size_t r1, i; + + /* Convert 128-byte blocks to PWXbytes blocks */ + /* 1: r_1 <-- 128r / PWXbytes */ + r1 = 128 * r / PWXbytes; + + /* 2: X <-- B'_{r_1 - 1} */ + blkcpy(X, &B[(r1 - 1) * PWXwords], PWXwords); + + /* 3: for i = 0 to r_1 - 1 do */ + for (i = 0; i < r1; i++) { + /* 4: if r_1 > 1 */ + if (r1 > 1) { + /* 5: X <-- X xor B'_i */ + blkxor(X, &B[i * PWXwords], PWXwords); + } + + /* 7: X <-- pwxform(X) */ + pwxform(X, ctx); + + /* 8: B'_i <-- X */ + blkcpy(&B[i * PWXwords], X, PWXwords); + } + + /* 10: i <-- floor((r_1 - 1) * PWXbytes / 64) */ + i = (r1 - 1) * PWXbytes / 64; + + /* 11: B_i <-- H(B_i) */ + salsa20(&B[i * 16], ctx->salsa20_rounds); + +#if 1 /* No-op with our current pwxform settings, but do it to make sure */ + /* 12: for i = i + 1 to 2r - 1 do */ + for (i++; i < 2 * r; i++) { + /* 13: B_i <-- H(B_i xor B_{i-1}) */ + blkxor(&B[i * 16], &B[(i - 1) * 16], 16); + salsa20(&B[i * 16], ctx->salsa20_rounds); + } +#endif +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint32_t integerify(const uint32_t *B, size_t r) +{ +/* + * Our 32-bit words are in host byte order. Also, they are SIMD-shuffled, but + * we only care about the least significant 32 bits anyway. + */ + const uint32_t *X = &B[(2 * r - 1) * 16]; + return X[0]; +} + +/** + * p2floor(x): + * Largest power of 2 not greater than argument. + */ +static uint32_t p2floor(uint32_t x) +{ + uint32_t y; + while ((y = x & (x - 1))) + x = y; + return x; +} + +/** + * wrap(x, i): + * Wrap x to the range 0 to i-1. + */ +static uint32_t wrap(uint32_t x, uint32_t i) +{ + uint32_t n = p2floor(i); + return (x & (n - 1)) + (i - n); +} + +/** + * smix1(B, r, N, V, X, ctx): + * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage X must be 128r bytes in length. + */ +static void smix1(uint32_t *B, size_t r, uint32_t N, + uint32_t *V, uint32_t *X, pwxform_ctx_t *ctx) +{ + size_t s = 32 * r; + uint32_t i, j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 2 * r; k++) + for (i = 0; i < 16; i++) + X[k * 16 + i] = le32dec(&B[k * 16 + (i * 5 % 16)]); + + if (ctx->version != YESPOWER_0_5) { + for (k = 1; k < r; k++) { + blkcpy(&X[k * 32], &X[(k - 1) * 32], 32); + blockmix_pwxform(&X[k * 32], ctx, 1); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i++) { + /* 3: V_i <-- X */ + blkcpy(&V[i * s], X, s); + + if (i > 1) { + /* j <-- Wrap(Integerify(X), i) */ + j = wrap(integerify(X, r), i); + + /* X <-- X xor V_j */ + blkxor(X, &V[j * s], s); + } + + /* 4: X <-- H(X) */ + if (V != ctx->S) + blockmix_pwxform(X, ctx, r); + else + blockmix_salsa(X, ctx->salsa20_rounds); + } + + /* B' <-- X */ + for (k = 0; k < 2 * r; k++) + for (i = 0; i < 16; i++) + le32enc(&B[k * 16 + (i * 5 % 16)], X[k * 16 + i]); +} + +/** + * smix2(B, r, N, Nloop, V, X, ctx): + * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in + * length; the temporary storage V must be 128rN bytes in length; the temporary + * storage X must be 128r bytes in length. The value N must be a power of 2 + * greater than 1. + */ +static void smix2(uint32_t *B, size_t r, uint32_t N, uint32_t Nloop, + uint32_t *V, uint32_t *X, pwxform_ctx_t *ctx) +{ + size_t s = 32 * r; + uint32_t i, j; + size_t k; + + /* X <-- B */ + for (k = 0; k < 2 * r; k++) + for (i = 0; i < 16; i++) + X[k * 16 + i] = le32dec(&B[k * 16 + (i * 5 % 16)]); + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < Nloop; i++) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8.1: X <-- X xor V_j */ + blkxor(X, &V[j * s], s); + /* V_j <-- X */ + if (Nloop != 2) + blkcpy(&V[j * s], X, s); + + /* 8.2: X <-- H(X) */ + blockmix_pwxform(X, ctx, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) + for (i = 0; i < 16; i++) + le32enc(&B[k * 16 + (i * 5 % 16)], X[k * 16 + i]); +} + +/** + * smix(B, r, N, p, t, V, X, ctx): + * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the + * temporary storage V must be 128rN bytes in length; the temporary storage + * X must be 128r bytes in length. The value N must be a power of 2 and at + * least 16. + */ +static void smix(uint32_t *B, size_t r, uint32_t N, + uint32_t *V, uint32_t *X, pwxform_ctx_t *ctx) +{ + uint32_t Nloop_all = (N + 2) / 3; /* 1/3, round up */ + uint32_t Nloop_rw = Nloop_all; + + Nloop_all++; Nloop_all &= ~(uint32_t)1; /* round up to even */ + if (ctx->version == YESPOWER_0_5) { + Nloop_rw &= ~(uint32_t)1; /* round down to even */ + } else { + Nloop_rw++; Nloop_rw &= ~(uint32_t)1; /* round up to even */ + } + + smix1(B, 1, ctx->Sbytes / 128, ctx->S, X, ctx); + smix1(B, r, N, V, X, ctx); + smix2(B, r, N, Nloop_rw /* must be > 2 */, V, X, ctx); + smix2(B, r, N, Nloop_all - Nloop_rw /* 0 or 2 */, V, X, ctx); +} + +/** + * yespower(local, src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * + * Return 0 on success; or -1 on error. + */ +int yespower(yespower_local_t *local, + const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst) +{ + yespower_version_t version = params->version; + uint32_t N = params->N; + uint32_t r = params->r; + const uint8_t *pers = params->pers; + size_t perslen = params->perslen; + int retval = -1; + size_t B_size, V_size; + uint32_t *B, *V, *X, *S; + pwxform_ctx_t ctx; + uint32_t sha256[8]; + + /* Sanity-check parameters */ + if ((version != YESPOWER_0_5 && version != YESPOWER_1_0) || + N < 1024 || N > 512 * 1024 || r < 8 || r > 32 || + (N & (N - 1)) != 0 || r < rmin || + (!pers && perslen)) { + errno = EINVAL; + return -1; + } + + /* Allocate memory */ + B_size = (size_t)128 * r; + V_size = B_size * N; + if ((V = malloc(V_size)) == NULL) + return -1; + if ((B = malloc(B_size)) == NULL) + goto free_V; + if ((X = malloc(B_size)) == NULL) + goto free_B; + ctx.version = version; + if (version == YESPOWER_0_5) { + ctx.salsa20_rounds = 8; + ctx.PWXrounds = PWXrounds_0_5; + ctx.Swidth = Swidth_0_5; + ctx.Sbytes = 2 * Swidth_to_Sbytes1(ctx.Swidth); + } else { + ctx.salsa20_rounds = 2; + ctx.PWXrounds = PWXrounds_1_0; + ctx.Swidth = Swidth_1_0; + ctx.Sbytes = 3 * Swidth_to_Sbytes1(ctx.Swidth); + } + if ((S = malloc(ctx.Sbytes)) == NULL) + goto free_X; + ctx.S = S; + ctx.S0 = (uint32_t (*)[2])S; + ctx.S1 = ctx.S0 + (1 << ctx.Swidth) * PWXsimple; + ctx.S2 = ctx.S1 + (1 << ctx.Swidth) * PWXsimple; + ctx.Smask = Swidth_to_Smask(ctx.Swidth); + ctx.w = 0; + + SHA256_Buf(src, srclen, (uint8_t *)sha256); + + if (version != YESPOWER_0_5) { + if (pers) { + src = pers; + srclen = perslen; + } else { + srclen = 0; + } + } + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256_YP((uint8_t *)sha256, sizeof(sha256), + src, srclen, 1, (uint8_t *)B, B_size); + + blkcpy(sha256, B, sizeof(sha256) / sizeof(sha256[0])); + + /* 3: B_i <-- MF(B_i, N) */ + smix(B, r, N, V, X, &ctx); + + if (version == YESPOWER_0_5) { + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256_YP((uint8_t *)sha256, sizeof(sha256), + (uint8_t *)B, B_size, 1, (uint8_t *)dst, sizeof(*dst)); + + if (pers) { + HMAC_SHA256_Buf(dst, sizeof(*dst), pers, perslen, + (uint8_t *)sha256); + SHA256_Buf(sha256, sizeof(sha256), (uint8_t *)dst); + } + } else { + HMAC_SHA256_Buf((uint8_t *)B + B_size - 64, 64, + sha256, sizeof(sha256), (uint8_t *)dst); + } + + /* Success! */ + retval = 0; + + /* Free memory */ + free(S); +free_X: + free(X); +free_B: + free(B); +free_V: + free(V); + + return retval; +} + +int yespower_tls(const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst) +{ +/* The reference implementation doesn't use thread-local storage */ + return yespower(NULL, src, srclen, params, dst); +} + +int yespower_init_local(yespower_local_t *local) +{ +/* The reference implementation doesn't use the local structure */ + local->base = local->aligned = NULL; + local->base_size = local->aligned_size = 0; + return 0; +} + +int yespower_free_local(yespower_local_t *local) +{ +/* The reference implementation frees its memory in yespower() */ + (void)local; /* unused */ + return 0; +} + +void yespower_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0 = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = NULL, + .perslen = 0 + }; + yespower_tls(input, 80, &yespower_1_0, (yespower_binary_t *)output); +} + +void yespowerIC_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_isotopec = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = (const uint8_t *)"IsotopeC", + .perslen = 8 + }; + yespower_tls(input, 80, &yespower_1_0_isotopec, (yespower_binary_t *)output); +} + +void yespowerIOTS_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_iots = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = (const uint8_t *)"Iots is committed to the development of IOT", + .perslen = 43 + }; + yespower_tls(input, 80, &yespower_1_0_iots, (yespower_binary_t *)output); +} + +void yespowerR16_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_r16 = { + .version = YESPOWER_1_0, + .N = 4096, + .r = 16, + .pers = NULL, + .perslen = 0 + }; + yespower_tls(input, 80, &yespower_1_0_r16, (yespower_binary_t *)output); +} + +void yespowerRES_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_resistance = { + .version = YESPOWER_1_0, + .N = 4096, + .r = 32, + .pers = NULL, + .perslen = 0 + }; + yespower_tls(input, 140, &yespower_1_0_resistance, (yespower_binary_t *)output); +} + +void yespowerSUGAR_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_sugarchain = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = (const uint8_t *)"Satoshi Nakamoto 31/Oct/2008 Proof-of-work is essentially one-CPU-one-vote", + .perslen = 74 + }; + yespower_tls(input, 80, &yespower_1_0_sugarchain, (yespower_binary_t *)output); +} + +void yespowerURX_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_uraniumx = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = (const uint8_t *)"UraniumX", + .perslen = 8 + }; + yespower_tls( input, len, &yespower_1_0_uraniumx, (yespower_binary_t *)output); +} + +void yespowerLTNCG_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_ltncg = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = (const uint8_t *)"LTNCGYES", + .perslen = 8 + }; + yespower_tls( input, len, &yespower_1_0_ltncg, (yespower_binary_t *)output); +} + +void yespowerLITB_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_litb = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = "LITBpower: The number of LITB working or available for proof-of-work mining", + .perslen = 73 + }; + yespower_tls( input, len, &yespower_1_0_litb, (yespower_binary_t *)output); +} + +void yespowerTIDE_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_tide = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 8, + .pers = NULL, + .perslen = 0 + }; + yespower_tls( input, len, &yespower_1_0_tide, (yespower_binary_t *)output); +} + +void cpupower_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_cpupower = + { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = "CPUpower: The number of CPU working or available for proof-of-work mining", + .perslen = 73 + }; + yespower_tls( input, len, &yespower_1_0_cpupower, (yespower_binary_t *)output); +} + +void power2b_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_b2b_power2b = + { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = "Now I am become Death, the destroyer of worlds", + .perslen = 46 + }; + yespower_b2b_tls( input, len, &yespower_b2b_power2b, (yespower_binary_t *)output); +} + +void yespowerMGPC_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_MGPC = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = "Magpies are birds of the Corvidae family.", + .perslen = 41 + }; + yespower_tls(input, len, &yespower_1_0_MGPC, (yespower_binary_t *)output); +} + +void yespowerARWN_hash(const char* input, char* output, uint32_t len) +{ + yespower_params_t yespower_1_0_ARWN = { + .version = YESPOWER_1_0, + .N = 2048, + .r = 32, + .pers = (const uint8_t *)"ARWN", + .perslen = 4 + }; + yespower_tls(input, len, &yespower_1_0_ARWN, (yespower_binary_t *)output); +} diff --git a/src/Native/libmultihash/yespower/yespower-platform.c b/src/Native/libmultihash/yespower/yespower-platform.c new file mode 100644 index 000000000..582d6a447 --- /dev/null +++ b/src/Native/libmultihash/yespower/yespower-platform.c @@ -0,0 +1,109 @@ +/*- + * Copyright 2013-2018 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __unix__ +#include +#endif + +#include "yespower.h" + +#define HUGEPAGE_THRESHOLD (12 * 1024 * 1024) + +#ifdef __x86_64__ +#define HUGEPAGE_SIZE (2 * 1024 * 1024) +#else +#undef HUGEPAGE_SIZE +#endif + +static void *alloc_region(yespower_region_t *region, size_t size) +{ + size_t base_size = size; + uint8_t *base, *aligned; +#ifdef MAP_ANON + int flags = +#ifdef MAP_NOCORE + MAP_NOCORE | +#endif + MAP_ANON | MAP_PRIVATE; +#if defined(MAP_HUGETLB) && defined(HUGEPAGE_SIZE) + size_t new_size = size; + const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1; + if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) { + flags |= MAP_HUGETLB; +/* + * Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of + * huge page size, so let's round up to huge page size here. + */ + new_size = size + hugepage_mask; + new_size &= ~hugepage_mask; + } + base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, flags, -1, 0); + if (base != MAP_FAILED) { + base_size = new_size; + } else if (flags & MAP_HUGETLB) { + flags &= ~MAP_HUGETLB; + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + } + +#else + base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); +#endif + if (base == MAP_FAILED) + base = NULL; + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **)&base, 64, size)) != 0) + base = NULL; + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) { + errno = ENOMEM; + } else if ((base = malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t)aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->base_size = base ? base_size : 0; + region->aligned_size = base ? size : 0; + return aligned; +} + +static inline void init_region(yespower_region_t *region) +{ + region->base = region->aligned = NULL; + region->base_size = region->aligned_size = 0; +} + +static int free_region(yespower_region_t *region) +{ + if (region->base) { +#ifdef MAP_ANON + if (munmap(region->base, region->base_size)) + return -1; +#else + free(region->base); +#endif + } + init_region(region); + return 0; +} \ No newline at end of file diff --git a/src/Native/libmultihash/yespower/yespower.h b/src/Native/libmultihash/yespower/yespower.h new file mode 100644 index 000000000..4dbd41337 --- /dev/null +++ b/src/Native/libmultihash/yespower/yespower.h @@ -0,0 +1,152 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013-2018 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _YESPOWER_H_ +#define _YESPOWER_H_ + +#include +#include /* for size_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Internal type used by the memory allocator. Please do not use it directly. + * Use yespower_local_t instead. + */ +typedef struct { + void *base, *aligned; + size_t base_size, aligned_size; +} yespower_region_t; + +/** + * Type for thread-local (RAM) data structure. + */ +typedef yespower_region_t yespower_local_t; + +/* + * Type for yespower algorithm version numbers. + */ +typedef enum { YESPOWER_0_5 = 5, YESPOWER_1_0 = 10 } yespower_version_t; + +/** + * yespower parameters combined into one struct. + */ +typedef struct { + yespower_version_t version; + uint32_t N, r; + const uint8_t *pers; + size_t perslen; +} yespower_params_t; + +/** + * A 256-bit yespower hash. + */ +typedef struct { + unsigned char uc[32]; +} yespower_binary_t; + +/** + * yespower_init_local(local): + * Initialize the thread-local (RAM) data structure. Actual memory allocation + * is currently fully postponed until a call to yespower(). + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yespower_init_local(yespower_local_t *local); + +/** + * yespower_free_local(local): + * Free memory that may have been allocated for an initialized thread-local + * (RAM) data structure. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as local is local to the thread. + */ +extern int yespower_free_local(yespower_local_t *local); + +/** + * yespower(local, src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * local is the thread-local data structure, allowing to preserve and reuse a + * memory allocation across calls, thereby reducing processing overhead. + * + * Return 0 on success; or -1 on error. + * + * local must be initialized with yespower_init_local(). + * + * MT-safe as long as local and dst are local to the thread. + */ +extern int yespower(yespower_local_t *local, + const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst); + +extern int yespower_b2b(yespower_local_t *local, + const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst); + +/** + * yespower_tls(src, srclen, params, dst): + * Compute yespower(src[0 .. srclen - 1], N, r), to be checked for "< target". + * The memory allocation is maintained internally using thread-local storage. + * + * Return 0 on success; or -1 on error. + * + * MT-safe as long as dst is local to the thread. + */ +extern int yespower_tls(const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst); + +extern int yespower_b2b_tls(const uint8_t *src, size_t srclen, + const yespower_params_t *params, yespower_binary_t *dst); + +void yespower_hash(const char* input, char* output, uint32_t len); +void yespowerIC_hash(const char* input, char* output, uint32_t len); +void yespowerIOTS_hash(const char* input, char* output, uint32_t len); +void yespowerLTNCG_hash(const char* input, char* output, uint32_t len); +void yespowerR16_hash(const char* input, char* output, uint32_t len); +void yespowerRES_hash(const char* input, char* output, uint32_t len); +void yespowerSUGAR_hash(const char* input, char* output, uint32_t len); +void yespowerURX_hash(const char* input, char* output, uint32_t len); +void yespowerLITB_hash(const char* input, char* output, uint32_t len); +void yespowerTIDE_hash(const char* input, char* output, uint32_t len); +void cpupower_hash(const char* input, char* output, uint32_t len); +void power2b_hash(const char* input, char* output, uint32_t len); +void yespowerMGPC_hash(const char* input, char* output, uint32_t len); +void yespowerARWN_hash(const char* input, char* output, uint32_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* !_YESPOWER_H_ */ \ No newline at end of file From e5a76845ef7a63b5eaa1fafb986958119108b807 Mon Sep 17 00:00:00 2001 From: ceedii Date: Tue, 31 Oct 2023 14:53:32 +0000 Subject: [PATCH 32/38] Revert to old PaymentSchemes --- .../Payments/PaymentSchemes/PPLNSPaymentScheme.cs | 4 +--- .../Payments/PaymentSchemes/PROPPaymentScheme.cs | 4 +--- .../Payments/PaymentSchemes/SOLOPaymentScheme.cs | 8 +------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs index b61a5b3db..a1b424ae5 100644 --- a/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/PPLNSPaymentScheme.cs @@ -84,11 +84,9 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, IMin // delete discarded shares if(shareCutOffDate.HasValue) { - // warning: some multichains coins like ALPH have none-linear blockHeight, so we CAN NOT discard old shares if older blocks are still pending - var pendingBlockBefore = await blockRepo.GetBlockBeforeCountAsync(con, poolConfig.Id, new[] { BlockStatus.Pending }, block.Created); var cutOffCount = await shareRepo.CountSharesBeforeAsync(con, tx, poolConfig.Id, shareCutOffDate.Value, ct); - if(cutOffCount > 0 && pendingBlockBefore < 1) + if(cutOffCount > 0) { await LogDiscardedSharesAsync(ct, poolConfig, block, shareCutOffDate.Value); diff --git a/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs index 9a5ee9c73..69c0b73b0 100644 --- a/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/PROPPaymentScheme.cs @@ -78,11 +78,9 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, IMin // delete discarded shares if(shareCutOffDate.HasValue) { - // warning: some multichains coins like ALPH have none-linear blockHeight, so we CAN NOT discard old shares if older blocks are still pending - var pendingBlockBefore = await blockRepo.GetBlockBeforeCountAsync(con, poolConfig.Id, new[] { BlockStatus.Pending }, block.Created); var cutOffCount = await shareRepo.CountSharesBeforeAsync(con, tx, poolConfig.Id, shareCutOffDate.Value, ct); - if(cutOffCount > 0 && pendingBlockBefore < 1) + if(cutOffCount > 0) { await LogDiscardedSharesAsync(ct, poolConfig, block, shareCutOffDate.Value); diff --git a/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs b/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs index aac23dd7b..9d87bd1ff 100644 --- a/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs +++ b/src/Miningcore/Payments/PaymentSchemes/SOLOPaymentScheme.cs @@ -15,20 +15,16 @@ public class SOLOPaymentScheme : IPayoutScheme { public SOLOPaymentScheme( IShareRepository shareRepo, - IBlockRepository blockRepo, IBalanceRepository balanceRepo) { Contract.RequiresNonNull(shareRepo); - Contract.RequiresNonNull(blockRepo); Contract.RequiresNonNull(balanceRepo); this.shareRepo = shareRepo; - this.blockRepo = blockRepo; this.balanceRepo = balanceRepo; } private readonly IBalanceRepository balanceRepo; - private readonly IBlockRepository blockRepo; private readonly IShareRepository shareRepo; private static readonly ILogger logger = LogManager.GetLogger("SOLO Payment", typeof(SOLOPaymentScheme)); @@ -59,11 +55,9 @@ public async Task UpdateBalancesAsync(IDbConnection con, IDbTransaction tx, IMin // delete discarded shares if(shareCutOffDate.HasValue) { - // warning: some multichains coins like ALPH have none-linear blockHeight, so we CAN NOT discard old shares if older blocks are still pending - var pendingBlockBefore = await blockRepo.GetBlockBeforeCountAsync(con, poolConfig.Id, new[] { BlockStatus.Pending }, block.Created); var cutOffCount = await shareRepo.CountSharesByMinerAsync(con, tx, poolConfig.Id, block.Miner, ct); - if(cutOffCount > 0 && pendingBlockBefore < 1) + if(cutOffCount > 0) { logger.Info(() => $"Deleting {cutOffCount} discarded shares for {block.Miner}"); From c483fd85c68551f1467e20863b7d9c8ae89e9aa7 Mon Sep 17 00:00:00 2001 From: ceedii Date: Tue, 31 Oct 2023 15:11:17 +0000 Subject: [PATCH 33/38] Revert to old Miningcore.csproj --- src/Miningcore/Miningcore.csproj | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index ae3a9825d..2878d8e5d 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -41,46 +41,46 @@ - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + - + - - - - - - - + + + + + + + - - - + + + - + From 571e39e84887caa6e61c381fed65244480e92719 Mon Sep 17 00:00:00 2001 From: ceedii Date: Tue, 31 Oct 2023 15:25:02 +0000 Subject: [PATCH 34/38] Revert to old dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index deee508fa..5a20a8e1b 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -27,4 +27,4 @@ jobs: - name: Build run: dotnet build --no-restore src - name: Test - run: dotnet test --logger:"console;verbosity=detailed" --no-build --verbosity normal src \ No newline at end of file + run: dotnet test --logger:"console;verbosity=detailed" --no-build --verbosity normal src From a88b84de0c5472678b7a9caeb58c9b8706a13557 Mon Sep 17 00:00:00 2001 From: ceedii Date: Sat, 30 Dec 2023 01:42:03 +0000 Subject: [PATCH 35/38] Add support for NEXA Add support for ZEPH Add support for KAS Add support for Debian 12 Fix major payment issue for public sub-address in the CryptonotePayoutHandler.cs Fix major issue with blockTemplate in the AlephiumJobManager.cs --- README.md | 37 +- build-debian-11.sh | 2 +- build-ubuntu-20.04.sh | 2 +- build-ubuntu-21.04.sh | 2 +- build-ubuntu-22.04.sh | 2 +- examples/kaspa_pool.json | 140 + examples/nexa_pool.json | 144 + examples/zephyr_pool.json | 148 + .../Api/Controllers/PoolApiController.cs | 123 +- .../Api/Extensions/MiningPoolExtensions.cs | 4 + .../Api/Responses/PagedResultResponse.cs | 4 +- src/Miningcore/AutofacModule.cs | 21 +- .../Blockchain/Alephium/AlephiumJobManager.cs | 155 +- .../Blockchain/Beam/BeamJobManager.cs | 2 +- .../Blockchain/Beam/BeamPayoutHandler.cs | 2 +- .../Bitcoin/BitcoinJobManagerBase.cs | 10 +- .../Bitcoin/BitcoinPayoutHandler.cs | 24 +- .../Blockchain/Conceal/ConcealJob.cs | 6 +- .../Conceal/ConcealPayoutHandler.cs | 2 +- .../Blockchain/Conceal/ConcealPool.cs | 5 + .../ConcealKeepAliveResponse.cs | 6 + .../Cryptonote/CryptonoteConstants.cs | 17 + .../Blockchain/Cryptonote/CryptonoteJob.cs | 13 +- .../Cryptonote/CryptonotePayoutHandler.cs | 77 +- .../Blockchain/Cryptonote/CryptonotePool.cs | 5 + .../DaemonResponses/GetBalanceResponse.cs | 16 + .../CryptonoteKeepAliveResponse.cs | 6 + .../Blockchain/Ethereum/EthereumConstants.cs | 9 +- .../Ethereum/EthereumPayoutHandler.cs | 22 +- .../KaspaPaymentProcessingConfigExtra.cs | 21 + .../Configuration/KaspaPoolConfigExtra.cs | 34 + .../Custom/Karlsencoin/KarlsencoinJob.cs | 12 + .../Blockchain/Kaspa/Custom/Pyrin/PyrinJob.cs | 21 + .../Blockchain/Kaspa/KaspaClientFactory.cs | 49 + .../Blockchain/Kaspa/KaspaConstants.cs | 87 + .../Kaspa/KaspaExtraNonceProvider.cs | 8 + src/Miningcore/Blockchain/Kaspa/KaspaJob.cs | 373 + .../Blockchain/Kaspa/KaspaJobManager.cs | 798 + .../Blockchain/Kaspa/KaspaPayoutHandler.cs | 449 + src/Miningcore/Blockchain/Kaspa/KaspaPool.cs | 431 + .../Blockchain/Kaspa/KaspaStratumMethods.cs | 39 + src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs | 668 + .../Blockchain/Kaspa/KaspaWorkerContext.cs | 27 + .../Blockchain/Kaspa/RPC/KaspaRPCClient.cs | 1 + .../Kaspa/RPC/KaspaWalletd/KaspaWalletd.cs | 3517 ++++ .../RPC/KaspaWalletd/KaspaWalletdGrpc.cs | 461 + .../Kaspa/RPC/KaspaWalletd/kaspawalletd.proto | 129 + .../Blockchain/Kaspa/RPC/Kaspad/Messages.cs | 5479 +++++ .../Kaspa/RPC/Kaspad/MessagesGrpc.cs | 236 + .../Blockchain/Kaspa/RPC/Kaspad/P2P.cs | 9278 ++++++++ .../Blockchain/Kaspa/RPC/Kaspad/Rpc.cs | 17549 ++++++++++++++++ .../Kaspa/RPC/Kaspad/messages.proto | 152 + .../Blockchain/Kaspa/RPC/Kaspad/p2p.proto | 291 + .../Blockchain/Kaspa/RPC/Kaspad/rpc.proto | 724 + .../Nexa/DaemonResponses/GetBlockResponse.cs | 12 + .../DaemonResponses/GetMiningCandidate.cs | 15 + .../DaemonResponses/SubmitMiningSolution.cs | 22 + .../Blockchain/Nexa/NexaCommands.cs | 8 + src/Miningcore/Blockchain/Nexa/NexaJob.cs | 178 + .../Blockchain/Nexa/NexaJobManager.cs | 349 + src/Miningcore/Blockchain/Nexa/NexaPool.cs | 389 + src/Miningcore/Configuration/ClusterConfig.cs | 42 +- .../Configuration/ClusterConfigExtensions.cs | 25 +- .../Crypto/Hashing/Algorithms/Blake2b.cs | 13 +- .../Crypto/Hashing/Algorithms/Blake3.cs | 13 +- .../Crypto/Hashing/Algorithms/CShake128.cs | 39 + .../Crypto/Hashing/Algorithms/CShake256.cs | 39 + .../Crypto/Hashing/Algorithms/NexaPow.cs | 84 + .../Crypto/Hashing/Algorithms/Shake128.cs | 22 + .../Crypto/Hashing/Algorithms/Shake256.cs | 22 + .../Crypto/Hashing/Ethash/Ethashb3/Cache.cs | 4 +- .../Hashing/Ethash/Ethashb3/Ethashb3Light.cs | 2 +- src/Miningcore/Miningcore.csproj | 21 +- src/Miningcore/Native/Cryptonote.cs | 24 +- src/Miningcore/Native/Multihash.cs | 16 +- src/Miningcore/Native/NexaPow.cs | 12 + .../Postgres/Repositories/BlockRepository.cs | 25 + .../Repositories/IBlockRepository.cs | 2 + src/Miningcore/Program.cs | 37 +- src/Miningcore/Util/ActionUtils.cs | 15 + src/Miningcore/build-libs-linux.sh | 7 +- src/Miningcore/coins.json | 115 +- src/Native/check_cpu.sh | 70 +- .../libbeamhash/crypto/blake/sse/blake2.h | 8 +- src/Native/libcryptonote/Makefile | 3 +- src/Native/libcryptonote/Makefile.MSys2 | 1 + src/Native/libcryptonote/cryptonote_config.h | 4 + .../cryptonote_core/cryptonote_basic.h | 120 +- .../cryptonote_format_utils.cpp | 38 +- src/Native/libcryptonote/exports.cpp | 26 +- .../serialization/zephyr_pricing_record.h | 126 + .../libcryptonote/zephyr_oracle/asset_types.h | 77 + .../zephyr_oracle/pricing_record.cpp | 259 + .../zephyr_oracle/pricing_record.h | 140 + src/Native/libmultihash/Lyra2.c | 383 +- src/Native/libmultihash/Lyra2.h | 4 +- src/Native/libmultihash/Makefile | 1 + src/Native/libmultihash/blake3/blake3.c | 21 + src/Native/libmultihash/blake3/blake3.h | 2 + src/Native/libmultihash/exports.cpp | 30 +- src/Native/libmultihash/libmultihash.vcxproj | 8 + .../libmultihash/libmultihash.vcxproj.filters | 24 + .../libmultihash/shake/crypto/cpu_endian.h | 428 + src/Native/libmultihash/shake/crypto/crypto.h | 403 + src/Native/libmultihash/shake/cshake.c | 277 + src/Native/libmultihash/shake/cshake.h | 75 + src/Native/libmultihash/shake/keccak.c | 511 + src/Native/libmultihash/shake/keccak.h | 138 + src/Native/libmultihash/shake/shake.c | 169 + src/Native/libmultihash/shake/shake.h | 72 + src/Native/libnexapow/Makefile | 20 + src/Native/libnexapow/exports.cpp | 19 + src/Native/libnexapow/schnorr.c | 62 + src/Native/libnexapow/schnorr.h | 18 + src/Native/libnexapow/schnorr_random.h | 84 + .../libnexapow/secp256k1/include/secp256k1.h | 771 + .../secp256k1/include/secp256k1_schnorr.h | 62 + src/Native/libubqhash/libubqhash.sln | 62 +- src/Native/libubqhash/libubqhash.vcxproj | 408 +- src/Native/libverushash/Makefile | 4 +- src/Native/libverushash/verushashverify.cpp | 3 + 121 files changed, 47621 insertions(+), 702 deletions(-) create mode 100644 examples/kaspa_pool.json create mode 100644 examples/nexa_pool.json create mode 100644 examples/zephyr_pool.json create mode 100644 src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealKeepAliveResponse.cs create mode 100644 src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteKeepAliveResponse.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPoolConfigExtra.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/Custom/Pyrin/PyrinJob.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaClientFactory.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaExtraNonceProvider.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaJob.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaPayoutHandler.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaPool.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaStratumMethods.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/KaspaRPCClient.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletd.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Messages.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/MessagesGrpc.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/messages.proto create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto create mode 100644 src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto create mode 100644 src/Miningcore/Blockchain/Nexa/DaemonResponses/GetBlockResponse.cs create mode 100644 src/Miningcore/Blockchain/Nexa/DaemonResponses/GetMiningCandidate.cs create mode 100644 src/Miningcore/Blockchain/Nexa/DaemonResponses/SubmitMiningSolution.cs create mode 100644 src/Miningcore/Blockchain/Nexa/NexaCommands.cs create mode 100644 src/Miningcore/Blockchain/Nexa/NexaJob.cs create mode 100644 src/Miningcore/Blockchain/Nexa/NexaJobManager.cs create mode 100644 src/Miningcore/Blockchain/Nexa/NexaPool.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/CShake128.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/CShake256.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/NexaPow.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Shake128.cs create mode 100644 src/Miningcore/Crypto/Hashing/Algorithms/Shake256.cs create mode 100644 src/Miningcore/Native/NexaPow.cs create mode 100644 src/Native/libcryptonote/serialization/zephyr_pricing_record.h create mode 100644 src/Native/libcryptonote/zephyr_oracle/asset_types.h create mode 100644 src/Native/libcryptonote/zephyr_oracle/pricing_record.cpp create mode 100644 src/Native/libcryptonote/zephyr_oracle/pricing_record.h create mode 100644 src/Native/libmultihash/shake/crypto/cpu_endian.h create mode 100644 src/Native/libmultihash/shake/crypto/crypto.h create mode 100644 src/Native/libmultihash/shake/cshake.c create mode 100644 src/Native/libmultihash/shake/cshake.h create mode 100644 src/Native/libmultihash/shake/keccak.c create mode 100644 src/Native/libmultihash/shake/keccak.h create mode 100644 src/Native/libmultihash/shake/shake.c create mode 100644 src/Native/libmultihash/shake/shake.h create mode 100644 src/Native/libnexapow/Makefile create mode 100644 src/Native/libnexapow/exports.cpp create mode 100644 src/Native/libnexapow/schnorr.c create mode 100644 src/Native/libnexapow/schnorr.h create mode 100644 src/Native/libnexapow/schnorr_random.h create mode 100644 src/Native/libnexapow/secp256k1/include/secp256k1.h create mode 100644 src/Native/libnexapow/secp256k1/include/secp256k1_schnorr.h diff --git a/README.md b/README.md index eef7db057..cc62cf352 100644 --- a/README.md +++ b/README.md @@ -23,16 +23,16 @@ Commercial support directly by the maintainer is available through [miningcore.pro](https://store.miningcore.pro). -For general questions visit the [Discussions Area](https://github.com/oliverw/miningcore/discussions). +For general questions visit the [Discussions Area](https://github.com/blackmennewstyle/miningcore/discussions). ## Contributions -Code contributions are very welcome and should be submitted as standard [pull requests](https://docs.github.com/en/pull-requests) (PR) based on the [`dev` branch](https://github.com/oliverw/miningcore/tree/dev). +Code contributions are very welcome and should be submitted as standard [pull requests](https://docs.github.com/en/pull-requests) (PR) based on the [`dev` branch](https://github.com/blackmennewstyle/miningcore/tree/dev). ## Building on Debian/Ubuntu ```console -git clone https://github.com/oliverw/miningcore +git clone https://github.com/blackmennewstyle/miningcore cd miningcore ``` @@ -55,7 +55,7 @@ or Download and install the [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) ```dosbatch -git clone https://github.com/oliverw/miningcore +git clone https://github.com/blackmennewstyle/miningcore cd miningcore build-windows.bat ``` @@ -69,7 +69,7 @@ build-windows.bat In case you don't want to install any dependencies then you can build the app using the official Microsoft .NET SDK Docker image. ```console -git clone https://github.com/oliverw/miningcore +git clone https://github.com/blackmennewstyle/miningcore cd miningcore ``` Then build using Docker: @@ -125,7 +125,7 @@ docker system prune -af ### Production OS -Windows is **not** a supported production environment. Only Linux is. Please do not file issues related to running a pool on Windows. Windows topics should be posted under [discussions](https://github.com/oliverw/miningcore/discussions). +Windows is **not** a supported production environment. Only Linux is. Please do not file issues related to running a pool on Windows. Windows topics should be posted under [discussions](https://github.com/blackmennewstyle/miningcore/discussions). Running and developing Miningcore on Windows is of course supported. @@ -187,7 +187,7 @@ Miningcore -c config.json ## Supported Currencies -Refer to [this file](https://github.com/oliverw/miningcore/blob/master/src/Miningcore/coins.json) for a complete list. +Refer to [this file](https://github.com/blackmennewstyle/miningcore/blob/master/src/Miningcore/coins.json) for a complete list. ## Caveats @@ -221,15 +221,14 @@ Once again, do not run a production pool on Windows! This is not a supported con ## Donations -To support this project you can become a [sponsor](https://github.com/sponsors/oliverw) or send a donation to the following accounts: - -* ETH: `miningcore.eth (ENS Address)` -* BTC: `miningcore.eth (ENS Address)` -* LTC: `miningcore.eth (ENS Address)` -* DOGE: `DGDuKRhBewGP1kbUz4hszNd2p6dDzWYy9Q` -* ETC: `0xF8cCE9CE143C68d3d4A7e6bf47006f21Cfcf93c0` -* DASH: `XqpBAV9QCaoLnz42uF5frSSfrJTrqHoxjp` -* ZEC: `t1YHZHz2DGVMJiggD2P4fBQ2TAPgtLSUwZ7` -* BTG: `GQb77ZuMCyJGZFyxpzqNfm7GB1rQreP4n6` -* ERGO: `9foYU8JkoqWBSDA3ba8VHfduPXV2NaVNPPAFkdYoR9t9cPQGMv4` -* XMR: `46S2AEwYmD9fnmZkxCpXf1T3U3DyEq3Ekb8Lg9kgUMGABn9Fp9q5nE2fBcXebrjrXfZHy5uC5HfLE6X4WLtSm35wUr9Mh46` +To support this project you can become a [sponsor]( https://github.com/sponsors//blackmennewstyle ) or send a donation to the following accounts: + +* ETH: `0xbC059e88A4dD11c2E882Fc6B83F8Ec12E4CCCFad` +* BTC: `16xvkGfG9nrJSKKo5nGWphP8w4hr2ZzVuw` +* LTC: `LLs76baYT7iMqQhizxtBC96Cy48iX3Eh1p` +* DOGE: `DFuvDSFh4N3SiXGDnye2Vbc8kqvMHbyQE1` +* KAS: `kaspa:qpmf0wyu7c5z4l82ax9cfc5ughwk2f9lgu8uckkqrrpjqkxuk7yrga5nntvgn` +* CCX: `ccx7S4B3gBeH1SGWCfqZp3NM7Vavg7H3S8ovJn8fU4bwC4vU7ChWfHtbNzifhrpbJ74bMDxj4KZFTcznTfsucCEg1Kgv7zbNgs` +* FIRO: `a5AsoTSkfPHQ3SUmR6binG1XW7oQQoFNU1` +* ERGO: `9gYyuZzaSw3TiCtUkSRuS3XVDUv41EFs3dtNCFGqiEwHqpb7gkF` +* XMR: `483zaHtMRfM7rw1dXgebhWaRR8QLgAF6w4BomAV319FVVHfdbYTLVuBRc4pQgRAnRpfy6CXvvwngK4Lo3mRKE29RRx3Jb5c` diff --git a/build-debian-11.sh b/build-debian-11.sh index 5ea3aafc6..87b3f46d5 100755 --- a/build-debian-11.sh +++ b/build-debian-11.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 build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5-dev + 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 (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-ubuntu-20.04.sh b/build-ubuntu-20.04.sh index d3fe3dd11..e0d514592 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 build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 + 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 (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-ubuntu-21.04.sh b/build-ubuntu-21.04.sh index c46ca983e..c377bfff5 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 build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 + 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 (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/build-ubuntu-22.04.sh b/build-ubuntu-22.04.sh index de1e3750c..26d8f0f76 100644 --- 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 dotnet-sdk-6.0 git cmake build-essential libssl-dev pkg-config libboost-all-dev libsodium-dev libzmq5 + 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 (cd src/Miningcore && \ BUILDIR=${1:-../../build} && \ diff --git a/examples/kaspa_pool.json b/examples/kaspa_pool.json new file mode 100644 index 000000000..41ee7b530 --- /dev/null +++ b/examples/kaspa_pool.json @@ -0,0 +1,140 @@ +{ + "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": "kas1", + "enabled": true, + "coin": "kaspa", + "address": "kaspa:qpee454h906cyt6pqr5gfegpxx7xjqp79dtwcqz8t698ugulhq8fxg56uaxm9", + "rewardRecipients": [ + { + "type": "op", + "address": "kaspa:qpee454h906cyt6pqr5gfegpxx7xjqp79dtwcqz8t698ugulhq8fxg56uaxm9", + "percentage": 1 + } + ], + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3094": { + "listenAddress": "0.0.0.0", + "difficulty": 4, + "varDiff": { + "minDiff": 2, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 100, + "maxDelta": 512 + } + }, + "3095": { + "listenAddress": "0.0.0.0", + "difficulty": 4, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 2, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 100, + "maxDelta": 512 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 16110, + "user": null, + "password": null, + "serviceName": "protowire.RPC" + }, + { + "host": "127.0.0.1", + "port": 8082, + "user": null, + "password": null, + "serviceName": "kaspawalletd.kaspawalletd", + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "walletPassword": "", + "minimumPayment": 1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} \ No newline at end of file diff --git a/examples/nexa_pool.json b/examples/nexa_pool.json new file mode 100644 index 000000000..d6a2634e2 --- /dev/null +++ b/examples/nexa_pool.json @@ -0,0 +1,144 @@ +{ + "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": "nexa1", + "enabled": true, + "coin": "nexa", + "address": "nexa:nqtsq5g59905h37stp0emhdjh3q2ll7d002cyjq0chegptj3", + "GBTArgs": [{ + "capabilities": [ + "coinbasetxn", + "workid", + "coinbase/append" + ], + "rules": [ + "segwit" + ] + }], + "rewardRecipients": [ + { + "type": "op", + "address": "nexa:nqtsq5g59905h37stp0emhdjh3q2ll7d002cyjq0chegptj3", + "percentage": 1 + } + ], + "blockRefreshInterval": 0, + "jobRebroadcastTimeout": 0, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3094": { + "listenAddress": "0.0.0.0", + "difficulty": 1, + "varDiff": { + "minDiff": 0.125, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3095": { + "listenAddress": "0.0.0.0", + "difficulty": 1, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 0.125, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 8888, + "user": "user", + "password": "pass", + "zmqBlockNotifySocket": "tcp://127.0.0.1:7226", + "zmqBlockNotifyTopic": "rawblock" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 100, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] +} diff --git a/examples/zephyr_pool.json b/examples/zephyr_pool.json new file mode 100644 index 000000000..e446a2be8 --- /dev/null +++ b/examples/zephyr_pool.json @@ -0,0 +1,148 @@ +{ + "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": "zeph1", + "enabled": true, + "coin": "zephyr", + "randomXRealm": "zeph1", + "address": "ZEPHYR2Kg7q4F8ujX4jy4dbcovSwsEMqHZyk7LUxLo8oSR8P6VKJkLNFmkvLBiTffGNNha378wMakebEq4rhtTV8U7ombhsKhGc5G", + "rewardRecipients": [ + { + "address": "ZEPHYR2Kg7q4F8ujX4jy4dbcovSwsEMqHZyk7LUxLo8oSR8P6VKJkLNFmkvLBiTffGNNha378wMakebEq4rhtTV8U7ombhsKhGc5G", + "percentage": 1 + } + ], + "blockRefreshInterval": 500, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3032": { + "listenAddress": "0.0.0.0", + "difficulty": 7500, + "name": "CPU Mining", + "varDiff": { + "minDiff": 1000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + }, + "3033": { + "listenAddress": "0.0.0.0", + "difficulty": 25000, + "name": "GPU Mining", + "varDiff": { + "minDiff": 10000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + }, + "3034": { + "listenAddress": "0.0.0.0", + "difficulty": 200000, + "name": "High-End Multi GPU Mining", + "varDiff": { + "minDiff": 200000, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 120, + "variancePercent": 30 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 18081, + "user": "user", + "password": "password" + }, + { + "host": "127.0.0.1", + "port": 18082, + "user": "user", + "password": "password", + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.25, + "minimumPaymentToPaymentId": 1.0, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 2.0 + } + } + }] +} diff --git a/src/Miningcore/Api/Controllers/PoolApiController.cs b/src/Miningcore/Api/Controllers/PoolApiController.cs index d84de8f7e..1fc031dd8 100644 --- a/src/Miningcore/Api/Controllers/PoolApiController.cs +++ b/src/Miningcore/Api/Controllers/PoolApiController.cs @@ -259,8 +259,9 @@ public async Task PagePoolMinersAsync( var blockStates = state is { Length: > 0 } ? state : new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; - - uint pageCount = (uint) Math.Floor((await cf.Run(con => blocksRepo.GetPoolBlockCountAsync(con, poolId, ct))) / (double) pageSize); + + uint itemCount = await cf.Run(con => blocksRepo.GetPoolBlockCountAsync(con, poolId, ct)); + uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); var blocks = (await cf.Run(con => blocksRepo.PageBlocksAsync(con, pool.Id, blockStates, page, pageSize, ct))) .Select(mapper.Map) @@ -286,7 +287,7 @@ public async Task PagePoolMinersAsync( } } - var response = new PagedResultResponse(blocks, pageCount); + var response = new PagedResultResponse(blocks, itemCount, pageCount); return response; } @@ -327,7 +328,8 @@ public async Task PagePoolMinersAsync( var pool = GetPool(poolId); var ct = HttpContext.RequestAborted; - uint pageCount = (uint) Math.Floor((await cf.Run(con => paymentsRepo.GetPaymentsCountAsync(con, poolId, null, ct))) / (double) pageSize); + uint itemCount = await cf.Run(con => paymentsRepo.GetPaymentsCountAsync(con, poolId, null, ct)); + uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); var payments = (await cf.Run(con => paymentsRepo.PagePaymentsAsync( con, pool.Id, null, page, pageSize, ct))) @@ -349,7 +351,7 @@ public async Task PagePoolMinersAsync( payment.AddressInfoLink = string.Format(addressInfobaseUrl, payment.Address); } - var response = new PagedResultResponse(payments, pageCount); + var response = new PagedResultResponse(payments, itemCount, pageCount); return response; } @@ -397,6 +399,98 @@ public async Task PagePoolMinersAsync( return stats; } + [HttpGet("{poolId}/miners/{address}/blocks")] + public async Task PageMinerBlocksAsync( + string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize = 15, [FromQuery] BlockStatus[] state = null) + { + var pool = GetPool(poolId); + var ct = HttpContext.RequestAborted; + + if(string.IsNullOrEmpty(address)) + throw new ApiException("Invalid or missing miner address", HttpStatusCode.NotFound); + + if(pool.Template.Family == CoinFamily.Ethereum) + address = address.ToLower(); + + var blockStates = state is { Length: > 0 } ? + state : + new[] { BlockStatus.Confirmed, BlockStatus.Pending, BlockStatus.Orphaned }; + + var blocks = (await cf.Run(con => blocksRepo.PageMinerBlocksAsync(con, pool.Id, address, blockStates, page, pageSize, ct))) + .Select(mapper.Map) + .ToArray(); + + // enrich blocks + var blockInfobaseDict = pool.Template.ExplorerBlockLinks; + + foreach(var block in blocks) + { + // compute infoLink + if(blockInfobaseDict != null) + { + blockInfobaseDict.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl); + + if(!string.IsNullOrEmpty(blockInfobaseUrl)) + { + if(blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) + block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); + else if(blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) + block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); + } + } + } + + return blocks; + } + + [HttpGet("/api/v2/pools/{poolId}/miners/{address}/blocks")] + public async Task> PageMinerBlocksV2Async( + string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize = 15, [FromQuery] BlockStatus[] state = null) + { + var pool = GetPool(poolId); + var ct = HttpContext.RequestAborted; + + if(string.IsNullOrEmpty(address)) + throw new ApiException("Invalid or missing miner address", HttpStatusCode.NotFound); + + if(pool.Template.Family == CoinFamily.Ethereum) + address = address.ToLower(); + + 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); + + var blocks = (await cf.Run(con => blocksRepo.PageMinerBlocksAsync(con, pool.Id, address, blockStates, page, pageSize, ct))) + .Select(mapper.Map) + .ToArray(); + + // enrich blocks + var blockInfobaseDict = pool.Template.ExplorerBlockLinks; + + foreach(var block in blocks) + { + // compute infoLink + if(blockInfobaseDict != null) + { + blockInfobaseDict.TryGetValue(!string.IsNullOrEmpty(block.Type) ? block.Type : "block", out var blockInfobaseUrl); + + if(!string.IsNullOrEmpty(blockInfobaseUrl)) + { + if(blockInfobaseUrl.Contains(CoinMetaData.BlockHeightPH)) + block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHeightPH, block.BlockHeight.ToString(CultureInfo.InvariantCulture)); + else if(blockInfobaseUrl.Contains(CoinMetaData.BlockHashPH) && !string.IsNullOrEmpty(block.Hash)) + block.InfoLink = blockInfobaseUrl.Replace(CoinMetaData.BlockHashPH, block.Hash); + } + } + } + + var response = new PagedResultResponse(blocks, itemCount, pageCount); + return response; + } + [HttpGet("{poolId}/miners/{address}/payments")] public async Task PageMinerPaymentsAsync( string poolId, string address, [FromQuery] int page, [FromQuery] int pageSize = 15) @@ -445,8 +539,9 @@ public async Task PagePoolMinersAsync( if(pool.Template.Family == CoinFamily.Ethereum) address = address.ToLower(); - - uint pageCount = (uint) Math.Floor((await cf.Run(con => paymentsRepo.GetPaymentsCountAsync(con, poolId, address, ct))) / (double) pageSize); + + uint itemCount = await cf.Run(con => paymentsRepo.GetPaymentsCountAsync(con, poolId, address, ct)); + uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); var payments = (await cf.Run(con => paymentsRepo.PagePaymentsAsync( con, pool.Id, address, page, pageSize, ct))) @@ -468,7 +563,7 @@ public async Task PagePoolMinersAsync( payment.AddressInfoLink = string.Format(addressInfobaseUrl, payment.Address); } - var response = new PagedResultResponse(payments, pageCount); + var response = new PagedResultResponse(payments, itemCount, pageCount); return response; } @@ -505,15 +600,16 @@ public async Task PagePoolMinersAsync( if(pool.Template.Family == CoinFamily.Ethereum) address = address.ToLower(); - - uint pageCount = (uint) Math.Floor((await cf.Run(con => paymentsRepo.GetBalanceChangesCountAsync(con, poolId, address))) / (double) pageSize); + + uint itemCount = await cf.Run(con => paymentsRepo.GetBalanceChangesCountAsync(con, poolId, address)); + uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); var balanceChanges = (await cf.Run(con => paymentsRepo.PageBalanceChangesAsync( con, pool.Id, address, page, pageSize, ct))) .Select(mapper.Map) .ToArray(); - var response = new PagedResultResponse(balanceChanges, pageCount); + var response = new PagedResultResponse(balanceChanges, itemCount, pageCount); return response; } @@ -550,13 +646,14 @@ public async Task> PageMinerEarningsByDayV2A if(pool.Template.Family == CoinFamily.Ethereum) address = address.ToLower(); - uint pageCount = (uint) Math.Floor((await cf.Run(con => paymentsRepo.GetMinerPaymentsByDayCountAsync(con, poolId, address))) / (double) pageSize); + uint itemCount = await cf.Run(con => paymentsRepo.GetMinerPaymentsByDayCountAsync(con, poolId, address)); + uint pageCount = (uint) Math.Floor(itemCount / (double) pageSize); var earnings = (await cf.Run(con => paymentsRepo.PageMinerPaymentsByDayAsync( con, pool.Id, address, page, pageSize, ct))) .ToArray(); - var response = new PagedResultResponse(earnings, pageCount); + var response = new PagedResultResponse(earnings, itemCount, pageCount); return response; } diff --git a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs index dd5e19187..03b1bbff9 100644 --- a/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs +++ b/src/Miningcore/Api/Extensions/MiningPoolExtensions.cs @@ -3,6 +3,7 @@ using Miningcore.Blockchain; using Miningcore.Blockchain.Alephium.Configuration; using Miningcore.Blockchain.Ergo.Configuration; +using Miningcore.Blockchain.Kaspa.Configuration; using Miningcore.Configuration; using Miningcore.Extensions; using Miningcore.Mining; @@ -39,6 +40,9 @@ public static PoolInfo ToPoolInfo(this PoolConfig poolConfig, IMapper mapper, Pe case "ergo": extra.StripValue(nameof(ErgoPaymentProcessingConfigExtra.WalletPassword)); break; + case "kaspa": + extra.StripValue(nameof(KaspaPaymentProcessingConfigExtra.WalletPassword)); + break; } } diff --git a/src/Miningcore/Api/Responses/PagedResultResponse.cs b/src/Miningcore/Api/Responses/PagedResultResponse.cs index 3bc123b85..dfe0873d0 100644 --- a/src/Miningcore/Api/Responses/PagedResultResponse.cs +++ b/src/Miningcore/Api/Responses/PagedResultResponse.cs @@ -2,10 +2,12 @@ namespace Miningcore.Api.Responses; public class PagedResultResponse : ResultResponse { - public PagedResultResponse(T result, uint pageCount) : base(result) + public PagedResultResponse(T result, uint itemCount, uint pageCount) : base(result) { + ItemCount = itemCount; PageCount = pageCount; } + public uint ItemCount { get; private set; } public uint PageCount { get; private set; } } diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index d105ffcec..bc4d963e2 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -10,6 +10,8 @@ using Miningcore.Blockchain.Equihash; using Miningcore.Blockchain.Ergo; using Miningcore.Blockchain.Ethereum; +using Miningcore.Blockchain.Kaspa; +using Miningcore.Blockchain.Nexa; using Miningcore.Blockchain.Progpow; using Miningcore.Configuration; using Miningcore.Crypto; @@ -186,11 +188,6 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType(); - ////////////////////// - // Ethereum - - builder.RegisterType(); - ////////////////////// // ZCash @@ -200,6 +197,20 @@ protected override void Load(ContainerBuilder builder) // Ergo builder.RegisterType(); + + ////////////////////// + // Ethereum + + builder.RegisterType(); + + ////////////////////// + // Kaspa + + builder.RegisterType(); + + ////////////////////// + // Nexa + builder.RegisterType(); ////////////////////// // Progpow diff --git a/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs b/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs index 3fc6438c4..ff8185a56 100644 --- a/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs +++ b/src/Miningcore/Blockchain/Alephium/AlephiumJobManager.cs @@ -66,7 +66,7 @@ protected IObservable AlephiumSubscribeStratumApiSocket { using(cts) { - retry: + socket_connexion: byte[] receiveBuffer = new byte[socketJobMessageBufferSize]; try @@ -91,10 +91,11 @@ protected IObservable AlephiumSubscribeStratumApiSocket // Message byte messageType; - int startOffset; - byte[] message; + uint messageLength; - MemoryStream memory; + MemoryStream memory = new MemoryStream(); + long remainingBytes; + byte[] remainingDataBytes; BinaryReader reader; // Job @@ -111,7 +112,6 @@ protected IObservable AlephiumSubscribeStratumApiSocket byte[] targetBlob; ChainInfo chainInfo; - logger.Debug(() => $"Sending request `{hello}`"); // send @@ -122,69 +122,98 @@ protected IObservable AlephiumSubscribeStratumApiSocket while(!cts.IsCancellationRequested && (receivedBytes = await stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length, cts.Token)) != 0) { logger.Debug(() => $"{receivedBytes} byte(s) of data have been received - current buffer size [{receiveBuffer.Length}]"); - - messageType = receiveBuffer[AlephiumConstants.MessageHeaderSize]; - if (messageType == AlephiumConstants.JobsMessageType) - { - logger.Debug(() => $"Job(s) received :D"); - startOffset = AlephiumConstants.MessageHeaderSize + 1; // 1 byte message type - message = new byte[receivedBytes - startOffset]; - Buffer.BlockCopy(receiveBuffer, startOffset, message, 0, receivedBytes - startOffset); - - using (memory = new MemoryStream(message)) + + // Append new received data to MemoryStream + memory.Seek(0, SeekOrigin.End); + memory.Write(receiveBuffer, 0, receivedBytes); + + // According to the ALPH reference pool, it's possible to receive more than 16 blockTemplate at once: https://github.com/alephium/mining-pool/commit/e94379b8fbf6f8b75aecb9b8e77b865de3679552 + // We need to handle properly that case scenario + socket_read_memory: + logger.Debug(() => $"MemoryStream: {memory.Length} byte(s)"); + + memory.Seek(0, SeekOrigin.Begin); + using (reader = new BinaryReader(memory, Encoding.UTF8, true)) { - using (reader = new BinaryReader(memory)) + messageLength = ReadBigEndianUInt32(reader); + logger.Debug(() => $"Message: {messageLength} byte(s)"); + + if((memory.Length >= AlephiumConstants.MessageHeaderSize) && (memory.Length >= messageLength + AlephiumConstants.MessageHeaderSize)) { - jobSize = ReadBigEndianUInt32(reader); - //logger.Debug(() => $"Parsing {jobSize} job(s)"); - - alephiumBlockTemplate = new AlephiumBlockTemplate[jobSize]; - - for (int index = 0; index < jobSize; index++) + // Read the message type + messageType = reader.ReadByte(); + if (messageType == AlephiumConstants.JobsMessageType) { - logger.Debug(() => $"Job ({index + 1})"); - fromGroup = (int)ReadBigEndianUInt32(reader); - toGroup = (int)ReadBigEndianUInt32(reader); - //logger.Debug(() => $"fromGroup: {fromGroup} - toGroup: {toGroup}"); - - chainInfo = await rpc.GetBlockflowChainInfoAsync(fromGroup, toGroup, cts.Token); - //logger.Debug(() => $"Height: {chainInfo?.CurrentHeight + 1}"); - - headerBlobLength = ReadBigEndianUInt32(reader); - //logger.Debug(() => $"headerBlobLength: {headerBlobLength}"); - headerBlob = reader.ReadBytes((int)headerBlobLength); - //logger.Debug(() => $"headerBlob: {headerBlob.ToHexString()}"); - - txsBlobLength = ReadBigEndianUInt32(reader); - //logger.Debug(() => $"txsBlobLength: {txsBlobLength}"); - txsBlob = reader.ReadBytes((int)txsBlobLength); - //logger.Debug(() => $"txsBlob: {txsBlob.ToHexString()}"); - - targetLength = ReadBigEndianUInt32(reader); - //logger.Debug(() => $"targetLength: {targetLength}"); - targetBlob = reader.ReadBytes((int)targetLength); - //logger.Debug(() => $"targetBlob: {targetBlob.ToHexString()}"); - - alephiumBlockTemplate[index] = new AlephiumBlockTemplate + jobSize = ReadBigEndianUInt32(reader); + logger.Debug(() => $"Parsing {jobSize} job(s) :D"); + + alephiumBlockTemplate = new AlephiumBlockTemplate[jobSize]; + + for (int index = 0; index < jobSize; index++) { - JobId = NextJobId("X"), - Height = (ulong) chainInfo?.CurrentHeight + 1, - Timestamp = clock.Now, - FromGroup = fromGroup, - ToGroup = toGroup, - HeaderBlob = headerBlob.ToHexString(), - TxsBlob = txsBlob.ToHexString(), - TargetBlob = targetBlob.ToHexString(), - ChainIndex = fromGroup * AlephiumConstants.GroupSize + toGroup, - }; + logger.Debug(() => $"Job ({index + 1})"); + fromGroup = (int)ReadBigEndianUInt32(reader); + toGroup = (int)ReadBigEndianUInt32(reader); + logger.Debug(() => $"fromGroup: {fromGroup} - toGroup: {toGroup}"); + + chainInfo = await rpc.GetBlockflowChainInfoAsync(fromGroup, toGroup, cts.Token); + logger.Debug(() => $"Height: {chainInfo?.CurrentHeight + 1}"); + + headerBlobLength = ReadBigEndianUInt32(reader); + logger.Debug(() => $"headerBlobLength: {headerBlobLength}"); + headerBlob = reader.ReadBytes((int)headerBlobLength); + logger.Debug(() => $"headerBlob: {headerBlob.ToHexString()}"); + + txsBlobLength = ReadBigEndianUInt32(reader); + logger.Debug(() => $"txsBlobLength: {txsBlobLength}"); + txsBlob = reader.ReadBytes((int)txsBlobLength); + logger.Debug(() => $"txsBlob: {txsBlob.ToHexString()}"); + + targetLength = ReadBigEndianUInt32(reader); + logger.Debug(() => $"targetLength: {targetLength}"); + targetBlob = reader.ReadBytes((int)targetLength); + logger.Debug(() => $"targetBlob: {targetBlob.ToHexString()}"); + + alephiumBlockTemplate[index] = new AlephiumBlockTemplate + { + JobId = NextJobId("X"), + Height = (ulong) chainInfo?.CurrentHeight + 1, + Timestamp = clock.Now, + FromGroup = fromGroup, + ToGroup = toGroup, + HeaderBlob = headerBlob.ToHexString(), + TxsBlob = txsBlob.ToHexString(), + TargetBlob = targetBlob.ToHexString(), + ChainIndex = fromGroup * AlephiumConstants.GroupSize + toGroup, + }; + } + + // publish + logger.Debug(() => $"Publishing {jobSize} {coin.Symbol} Block Template(s)..."); + obs.OnNext(alephiumBlockTemplate); + } + + remainingBytes = memory.Length - memory.Position; + if(remainingBytes > 0) + { + logger.Debug(() => $"More job(s) are available :O"); + + remainingDataBytes = reader.ReadBytes((int) remainingBytes); + memory.SetLength(0); + memory.Write(remainingDataBytes, 0, remainingDataBytes.Length); + + goto socket_read_memory; + } + else + { + logger.Debug(() => $"All available data have been digested.."); + + memory.SetLength(0); } - - // publish - //logger.Debug(() => $"Publishing..."); - obs.OnNext(alephiumBlockTemplate); } + else + logger.Warn(() => $"Message is more bigger than MemoryStream, so we can not diggest completely those data, they will be temporarly ignored until we are able to identify a complete message. Maybe consider to increase `'socketJobMessageBufferSize': {socketJobMessageBufferSize * 2}`"); } - } } logger.Debug(() => $"No more data received. Bye!"); @@ -204,7 +233,7 @@ protected IObservable AlephiumSubscribeStratumApiSocket if(!cts.IsCancellationRequested) { await Task.Delay(TimeSpan.FromSeconds(10), cts.Token); - goto retry; + goto socket_connexion; } } }, cts.Token); @@ -642,7 +671,7 @@ public override void Configure(PoolConfig pc, ClusterConfig cc) extraPoolConfig = pc.Extra.SafeExtensionDataAs(); extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); - maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 16; + maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 8; socketJobMessageBufferSize = extraPoolConfig?.SocketJobMessageBufferSize ?? 131072; // extract standard daemon endpoints diff --git a/src/Miningcore/Blockchain/Beam/BeamJobManager.cs b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs index 3d126759a..13a1e34d9 100644 --- a/src/Miningcore/Blockchain/Beam/BeamJobManager.cs +++ b/src/Miningcore/Blockchain/Beam/BeamJobManager.cs @@ -61,7 +61,7 @@ public BeamJobManager( private RpcClient walletRpc; private IHttpClientFactory httpClientFactory; private SimpleRestClient explorerRestClient; - private BeamHash solver = new BeamHash {}; + private BeamHash solver = new BeamHash(); private readonly IMasterClock clock; private readonly IExtraNonceProvider extraNonceProvider; protected int maxActiveJobs = 4; diff --git a/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs b/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs index 8820ba7c3..604bbe0d0 100644 --- a/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Beam/BeamPayoutHandler.cs @@ -102,7 +102,7 @@ private async Task EnsureBalance(decimal requiredAmount, BeamCoinTemplate return false; } - var balance = Math.Floor(response.Response.Balance / BeamConstants.SmallestUnit); + var balance = response.Response.Balance / BeamConstants.SmallestUnit; if(balance < requiredAmount) { diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs index 085fa11f1..4c0dc5ad5 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinJobManagerBase.cs @@ -49,6 +49,7 @@ protected BitcoinJobManagerBase( protected DateTime? lastJobRebroadcast; protected bool hasSubmitBlockMethod; protected bool isPoS; + protected bool forcePoolAddressDestinationWithPubKey; protected TimeSpan jobRebroadcastTimeout; protected Network network; protected IDestination poolAddressDestination; @@ -464,7 +465,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) // chain detection if(!hasLegacyDaemon) - network = Network.GetNetwork(blockchainInfoResponse.Chain.ToLower()); + network = (blockchainInfoResponse.Chain.ToLower() == "nexa") ? Network.Main : Network.GetNetwork(blockchainInfoResponse.Chain.ToLower()); else network = daemonInfoResponse.Testnet ? Network.TestNet : Network.Main; @@ -476,9 +477,11 @@ protected override async Task PostStartInitAsync(CancellationToken ct) isPoS = poolConfig.Template is BitcoinTemplate {IsPseudoPoS: true} || (difficultyResponse.Values().Any(x => x.Path == "proof-of-stake" && !difficultyResponse.Values().Any(x => x.Path == "proof-of-work"))); + + forcePoolAddressDestinationWithPubKey = poolConfig.Template is BitcoinTemplate {ForcePoolAddressDestinationWithPubKey: true}; // Create pool address script from response - if(!isPoS) + if(!isPoS && !forcePoolAddressDestinationWithPubKey) { if(extraPoolConfig != null && extraPoolConfig.AddressType != BitcoinAddressType.Legacy) logger.Info(()=> $"Interpreting pool address {poolConfig.Address} as type {extraPoolConfig?.AddressType.ToString()}"); @@ -487,7 +490,10 @@ protected override async Task PostStartInitAsync(CancellationToken ct) } else + { + logger.Info(()=> $"Interpreting pool address {poolConfig.Address} as raw public key"); poolAddressDestination = new PubKey(poolConfig.PubKey ?? validateAddressResponse.PubKey); + } // Payment-processing setup if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) diff --git a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs index 691deb33f..70c077c9d 100644 --- a/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Bitcoin/BitcoinPayoutHandler.cs @@ -21,7 +21,7 @@ namespace Miningcore.Blockchain.Bitcoin; -[CoinFamily(CoinFamily.Bitcoin)] +[CoinFamily(CoinFamily.Bitcoin, CoinFamily.Nexa)] public class BitcoinPayoutHandler : PayoutHandlerBase, IPayoutHandler { @@ -50,6 +50,10 @@ public BitcoinPayoutHandler( protected BitcoinDaemonEndpointConfigExtra extraPoolEndpointConfig; protected BitcoinPoolPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + private int payoutDecimalPlaces = 4; + private CoinTemplate coin; + private int minConfirmations; + protected override string LogCategory => "Bitcoin Payout Handler"; #region IPayoutHandler @@ -65,6 +69,15 @@ public virtual Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, Cancellation extraPoolEndpointConfig = pc.Extra.SafeExtensionDataAs(); extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + coin = poolConfig.Template.As(); + if(coin is BitcoinTemplate bitcoinTemplate) + { + minConfirmations = extraPoolEndpointConfig?.MinimumConfirmations ?? bitcoinTemplate.CoinbaseMinConfimations ?? BitcoinConstants.CoinbaseMinConfimations; + payoutDecimalPlaces = bitcoinTemplate.PayoutDecimalPlaces ?? 4; + } + else + minConfirmations = extraPoolEndpointConfig?.MinimumConfirmations ?? BitcoinConstants.CoinbaseMinConfimations; + logger = LogUtil.GetPoolScopedLogger(typeof(BitcoinPayoutHandler), pc); var jsonSerializerSettings = ctx.Resolve(); @@ -78,16 +91,9 @@ public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] 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(); - int minConfirmations; - - if(coin is BitcoinTemplate bitcoinTemplate) - minConfirmations = extraPoolEndpointConfig?.MinimumConfirmations ?? bitcoinTemplate.CoinbaseMinConfimations ?? BitcoinConstants.CoinbaseMinConfimations; - else - minConfirmations = extraPoolEndpointConfig?.MinimumConfirmations ?? BitcoinConstants.CoinbaseMinConfimations; for(var i = 0; i < pageCount; i++) { @@ -191,7 +197,7 @@ public virtual async Task PayoutAsync(IMiningPool pool, Balance[] balances, Canc // build args var amounts = balances .Where(x => x.Amount > 0) - .ToDictionary(x => x.Address, x => Math.Round(x.Amount, 4)); + .ToDictionary(x => x.Address, x => Math.Round(x.Amount, payoutDecimalPlaces)); if(amounts.Count == 0) return; diff --git a/src/Miningcore/Blockchain/Conceal/ConcealJob.cs b/src/Miningcore/Blockchain/Conceal/ConcealJob.cs index c37df5618..c699b50f0 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealJob.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealJob.cs @@ -26,6 +26,7 @@ public ConcealJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, str PrevHash = prevHash; hashFunc = hashFuncs[coin.Hash]; + blobType = coin.BlobType; } protected delegate void HashFunc(ReadOnlySpan data, Span result, ulong height); @@ -39,6 +40,7 @@ public ConcealJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, str private byte[] blobTemplate; private int extraNonce; private readonly HashFunc hashFunc; + private readonly int blobType; private void PrepareBlobTemplate(byte[] instanceId) { @@ -57,7 +59,7 @@ private string EncodeBlob(uint workerExtraNonce) var bytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); bytes.CopyTo(blob[BlockTemplate.ReservedOffset..]); - return CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length).ToHexString(); + return CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length, blobType).ToHexString(); } private string EncodeTarget(double difficulty, int size = 4) @@ -130,7 +132,7 @@ public void PrepareWorkerJob(ConcealWorkerJob workerJob, out string blob, out st bytes.CopyTo(blob[ConcealConstants.BlobNonceOffset..]); // convert - var blobConverted = CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length); + var blobConverted = CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length, blobType); if(blobConverted == null) throw new StratumException(StratumError.MinusOne, "malformed blob"); diff --git a/src/Miningcore/Blockchain/Conceal/ConcealPayoutHandler.cs b/src/Miningcore/Blockchain/Conceal/ConcealPayoutHandler.cs index 22bc78164..824e79499 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealPayoutHandler.cs @@ -102,7 +102,7 @@ private async Task EnsureBalance(decimal requiredAmount, ConcealCoinTempla return false; } - var balance = Math.Floor(response.Response.Balance / coin.SmallestUnit); + var balance = response.Response.Balance / coin.SmallestUnit; if(balance < requiredAmount) { diff --git a/src/Miningcore/Blockchain/Conceal/ConcealPool.cs b/src/Miningcore/Blockchain/Conceal/ConcealPool.cs index 99806e998..a2e6c43d7 100644 --- a/src/Miningcore/Blockchain/Conceal/ConcealPool.cs +++ b/src/Miningcore/Blockchain/Conceal/ConcealPool.cs @@ -383,6 +383,11 @@ protected override async Task OnRequestAsync(StratumConnection connection, case ConcealStratumMethods.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 + await connection.RespondAsync(new ConcealKeepAliveResponse(), request.Id); break; default: diff --git a/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealKeepAliveResponse.cs b/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealKeepAliveResponse.cs new file mode 100644 index 000000000..7e297c118 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealKeepAliveResponse.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Conceal.StratumResponses; + +public class ConcealKeepAliveResponse +{ + public string Status { get; set; } = "KEEPALIVED"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs index d9ef412aa..7a611c8d7 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteConstants.cs @@ -42,6 +42,23 @@ public static class CryptonoteConstants public const decimal StaticTransactionFeeReserve = 0.03m; // in monero } +public static class ZephyrConstants +{ + public const int BlobType = 13; + // ZEPH Block reward distribution + // https://medium.com/@zephyrcurrencyprotocol/zephyr-protocol-tokenomics-information-3f83531f453a + public const ulong OsirisHardForkBlockMainnet = 89300; + public const ulong OsirisHardForkBlockTestnet = 100; + public const ulong OsirisHardForkBlockStagenet = 100; + // Percentage + public const decimal OsirisHardForkMiningReward = 0.75m; + public const decimal OsirisHardForkReserveReward = 0.20m; + public const decimal OsirisHardForkGovernanceReward = 0.05m; + public const decimal MiningRewardInitial = 0.95m; + public const decimal ReserveRewardInitial = 0.00m; + public const decimal GovernanceRewardInitial = 0.05m; +} + public static class CryptonoteCommands { public const string GetInfo = "get_info"; diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs index a0ce6bdf3..90598d719 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs @@ -27,6 +27,7 @@ public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, RandomXRealm = randomXRealm; hashFunc = hashFuncs[coin.Hash]; + blobType = coin.BlobType; } protected delegate void HashFunc(string realm, string seedHex, ReadOnlySpan data, Span result, ulong height); @@ -63,6 +64,7 @@ public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, private byte[] blobTemplate; private int extraNonce; private readonly HashFunc hashFunc; + private readonly int blobType; private void PrepareBlobTemplate(byte[] instanceId) { @@ -81,7 +83,7 @@ private string EncodeBlob(uint workerExtraNonce) var bytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); bytes.CopyTo(blob[BlockTemplate.ReservedOffset..]); - return CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length).ToHexString(); + return CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length, blobType).ToHexString(); } private string EncodeTarget(double difficulty, int size = 4) @@ -156,7 +158,7 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out bytes.CopyTo(blob[CryptonoteConstants.BlobNonceOffset..]); // convert - var blobConverted = CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length); + var blobConverted = CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length, blobType); if(blobConverted == null) throw new StratumException(StratumError.MinusOne, "malformed blob"); @@ -204,7 +206,12 @@ public void PrepareWorkerJob(CryptonoteWorkerJob workerJob, out string blob, out { // Compute block hash Span blockHash = stackalloc byte[32]; - ComputeBlockHash(blobConverted, blockHash); + + // Not all Cryptonote coins are equal + if(blobType == ZephyrConstants.BlobType) + CryptonoteBindings.GetBlockId(blob, blockHash, blobType); + else + ComputeBlockHash(blobConverted, blockHash); // Fill in block-relevant fields result.IsBlockCandidate = true; diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs index f3cc1105c..ea2963aae 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePayoutHandler.cs @@ -141,16 +141,44 @@ private async Task UpdateNetworkTypeAsync(CancellationToken ct) private async Task EnsureBalance(decimal requiredAmount, CryptonoteCoinTemplate coin, CancellationToken ct) { - var response = await rpcClientWallet.ExecuteAsync(logger, CryptonoteWalletCommands.GetBalance, ct); + decimal unlockedBalance = 0.0m; + decimal balance = 0.0m; - if(response.Error != null) + // Not all Cryptonote coins are equal + switch(coin.Symbol) { - logger.Error(() => $"[{LogCategory}] Daemon command '{CryptonoteWalletCommands.GetBalance}' returned error: {response.Error.Message} code {response.Error.Code}"); - return false; - } + case "ZEPH": + var responseBalances = await rpcClientWallet.ExecuteAsync(logger, CryptonoteWalletCommands.GetBalance, ct); + + if(responseBalances.Error != null) + { + logger.Error(() => $"[{LogCategory}] Daemon command '{CryptonoteWalletCommands.GetBalance}' returned error: {responseBalances.Error.Message} code {responseBalances.Error.Code}"); + return false; + } + + var balances = responseBalances.Response.Balances + .Where(x => x.Asset == coin.Symbol) + .ToArray(); + + if(balances.Length > 0) + { + unlockedBalance = balances.Sum(x => (x.UnlockedBalance / coin.SmallestUnit)); + balance = balances.Sum(x => (x.Balance / coin.SmallestUnit)); + } + break; + default: + var responseBalance = await rpcClientWallet.ExecuteAsync(logger, CryptonoteWalletCommands.GetBalance, ct); - var unlockedBalance = Math.Floor(response.Response.UnlockedBalance / coin.SmallestUnit); - var balance = Math.Floor(response.Response.Balance / coin.SmallestUnit); + if(responseBalance.Error != null) + { + logger.Error(() => $"[{LogCategory}] Daemon command '{CryptonoteWalletCommands.GetBalance}' returned error: {responseBalance.Error.Message} code {responseBalance.Error.Code}"); + return false; + } + + unlockedBalance = responseBalance.Response.UnlockedBalance / coin.SmallestUnit; + balance = responseBalance.Response.Balance / coin.SmallestUnit; + break; + } if(unlockedBalance < requiredAmount) { @@ -403,7 +431,35 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, { block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; - block.Reward = (blockHeader.Reward / coin.SmallestUnit) * coin.BlockrewardMultiplier; + + // Not all Cryptonote coins are equal + switch(coin.Symbol) + { + case "ZEPH": + ulong osirisHardForkBlock = ZephyrConstants.OsirisHardForkBlockMainnet; + decimal miningReward = ZephyrConstants.MiningRewardInitial; + decimal reserveReward = ZephyrConstants.ReserveRewardInitial; + + if(networkType == CryptonoteNetworkType.Test || networkType == CryptonoteNetworkType.Stage) + { + if(networkType == CryptonoteNetworkType.Test) + osirisHardForkBlock = ZephyrConstants.OsirisHardForkBlockTestnet; + else + osirisHardForkBlock = ZephyrConstants.OsirisHardForkBlockStagenet; + + miningReward = ZephyrConstants.OsirisHardForkMiningReward; + reserveReward = ZephyrConstants.OsirisHardForkReserveReward; + } + + if(block.BlockHeight >= osirisHardForkBlock) + logger.Debug(() => $"[{LogCategory}] Osiris fork period detected..."); + + block.Reward = (((blockHeader.Reward / coin.SmallestUnit) / (1m - reserveReward)) * miningReward) * coin.BlockrewardMultiplier; + break; + default: + block.Reward = (blockHeader.Reward / coin.SmallestUnit) * coin.BlockrewardMultiplier; + break; + } logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); @@ -435,7 +491,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation #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 < 3) + infoResponse.Response.IncomingConnectionsCount + infoResponse.Response.OutgoingConnectionsCount < 2) { logger.Warn(() => $"[{LogCategory}] Payout aborted. Not enough peers (4 required)"); return; @@ -454,6 +510,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation { case CryptonoteNetworkType.Main: if(addressPrefix != coin.AddressPrefix && + addressPrefix != coin.SubAddressPrefix && addressIntegratedPrefix != coin.AddressPrefixIntegrated) { logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address: {x.Address}"); @@ -464,6 +521,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation case CryptonoteNetworkType.Stage: if(addressPrefix != coin.AddressPrefixStagenet && + addressPrefix != coin.SubAddressPrefixStagenet && addressIntegratedPrefix != coin.AddressPrefixIntegratedStagenet) { logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address: {x.Address}"); @@ -474,6 +532,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation case CryptonoteNetworkType.Test: if(addressPrefix != coin.AddressPrefixTestnet && + addressPrefix != coin.SubAddressPrefixTestnet && addressIntegratedPrefix != coin.AddressPrefixIntegratedTestnet) { logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address: {x.Address}"); diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs index 5944ad407..09f69db77 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonotePool.cs @@ -381,6 +381,11 @@ protected override async Task OnRequestAsync(StratumConnection connection, case CryptonoteStratumMethods.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 + await connection.RespondAsync(new CryptonoteKeepAliveResponse(), request.Id); break; default: diff --git a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs index c70c9ff01..1918832b4 100644 --- a/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs +++ b/src/Miningcore/Blockchain/Cryptonote/DaemonResponses/GetBalanceResponse.cs @@ -9,3 +9,19 @@ public class GetBalanceResponse [JsonProperty("unlocked_balance")] public decimal UnlockedBalance { get; set; } } + +public class BalanceAsset +{ + [JsonProperty("asset_type")] + public string Asset { get; set; } = null; + + public decimal Balance { get; set; } + + [JsonProperty("unlocked_balance")] + public decimal UnlockedBalance { get; set; } +} + +public class GetBalancesResponse +{ + public BalanceAsset[] Balances { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteKeepAliveResponse.cs b/src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteKeepAliveResponse.cs new file mode 100644 index 000000000..059f3b130 --- /dev/null +++ b/src/Miningcore/Blockchain/Cryptonote/StratumResponses/CryptonoteKeepAliveResponse.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Cryptonote.StratumResponses; + +public class CryptonoteKeepAliveResponse +{ + public string Status { get; set; } = "KEEPALIVED"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs index 68d80993d..b06fba52c 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs @@ -95,8 +95,9 @@ public class PinkConstants public const decimal BaseRewardInitial = 1.0m; } -// Rethereum -public class RethereumConstants +// Hypra +// https://github.com/Rethereum-blockchain/open-rethereum-pool/blob/master/payouts/unlocker.go +public class HypraConstants { public const ulong EpochLength = 32000; public const ulong LondonHeight = 15787969; @@ -138,7 +139,7 @@ public enum EthereumNetworkType Pink = 10100, OctaSpace = 800001, OctaSpaceTestnet = 800002, - Rethereum = 622277, + Hypra = 622277, Unknown = -1, } @@ -156,7 +157,7 @@ public enum GethChainType Pink = 10100, OctaSpace, OctaSpaceTestnet, - Rethereum, + Hypra, Unknown = -1, } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index 86feadaa6..62d7ee09e 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -166,7 +166,7 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, var gasUsed = blockHashResponse.Response.GasUsed; var burnedFee = (decimal) 0; - if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink" || extraPoolConfig?.ChainTypeOverride == "Rethereum") + if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink" || extraPoolConfig?.ChainTypeOverride == "Hypra") burnedFee = (baseGas * gasUsed / EthereumConstants.Wei); block.Hash = blockHash; @@ -298,7 +298,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation // ensure we have 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 == "Rethereum") && + 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") && (infoResponse.Error != null || string.IsNullOrEmpty(infoResponse.Response) || infoResponse.Response.IntegralFromHex() < EthereumConstants.MinPayoutPeerCount)) { @@ -433,15 +433,15 @@ internal static decimal GetBaseBlockReward(GethChainType chainType, ulong height return OctaSpaceConstants.BaseRewardInitial; - case GethChainType.Rethereum: - if(height >= RethereumConstants.LondonHeight) - return RethereumConstants.LondonBlockReward; - if(height >= RethereumConstants.ArrowGlacierHeight) - return RethereumConstants.ArrowGlacierBlockReward; - if(height >= RethereumConstants.GrayGlacierHeight) - return RethereumConstants.GrayGlacierBlockReward; + case GethChainType.Hypra: + if(height >= HypraConstants.LondonHeight) + return HypraConstants.LondonBlockReward; + if(height >= HypraConstants.ArrowGlacierHeight) + return HypraConstants.ArrowGlacierBlockReward; + if(height >= HypraConstants.GrayGlacierHeight) + return HypraConstants.GrayGlacierBlockReward; - return RethereumConstants.BaseRewardInitial; + return HypraConstants.BaseRewardInitial; default: throw new Exception("Unable to determine block reward: Unsupported chain type"); @@ -496,7 +496,7 @@ internal static decimal GetUncleReward(GethChainType chainType, ulong uheight, u reward = 0; break; - case GethChainType.Rethereum: + case GethChainType.Hypra: reward = 0.1m; break; diff --git a/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs new file mode 100644 index 000000000..280e4b254 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPaymentProcessingConfigExtra.cs @@ -0,0 +1,21 @@ +namespace Miningcore.Blockchain.Kaspa.Configuration; + +public class KaspaPaymentProcessingConfigExtra +{ + /// + /// Password for unlocking wallet + /// + public string WalletPassword { get; set; } + + /// + /// Minimum block confirmations + /// Default: 10 + /// + 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/Kaspa/Configuration/KaspaPoolConfigExtra.cs b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPoolConfigExtra.cs new file mode 100644 index 000000000..93372cb73 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/Configuration/KaspaPoolConfigExtra.cs @@ -0,0 +1,34 @@ +using Miningcore.Configuration; + +namespace Miningcore.Blockchain.Kaspa.Configuration; + +public class KaspaPoolConfigExtra +{ + /// + /// Maximum number of tracked jobs. + /// Default: 8 + /// + public int? MaxActiveJobs { get; set; } + + /// + /// Arbitrary string added in the Kaspa coinbase tx + /// Default: "Miningcore.developers["Cedric CRISPIN"]" + /// + public string ExtraData { get; set; } + + public int? ExtraNonce1Size { get; set; } + + /// + /// Optional: Daemon RPC service name override + /// Should match the value of .proto file + /// Default: "protowire.RPC" + /// + public string ProtobufDaemonRpcServiceName { get; set; } + + /// + /// Optional: Wallet RPC service name override + /// Should match the value of .proto file + /// Default: "kaspawalletd.kaspawalletd" + /// + public string ProtobufWalletRpcServiceName { get; set; } +} diff --git a/src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs b/src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs new file mode 100644 index 000000000..09dec9b46 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/Custom/Karlsencoin/KarlsencoinJob.cs @@ -0,0 +1,12 @@ +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; + +namespace Miningcore.Blockchain.Kaspa.Custom.Karlsencoin; + +public class KarlsencoinJob : KaspaJob +{ + public KarlsencoinJob() + { + this.coinbaseHasher = new Blake3(); + } +} \ 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 new file mode 100644 index 000000000..787d7b3a9 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/Custom/Pyrin/PyrinJob.cs @@ -0,0 +1,21 @@ +using System.Text; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; + +namespace Miningcore.Blockchain.Kaspa.Custom.Pyrin; + +public class PyrinJob : KaspaJob +{ + public PyrinJob(long blockHeight) + { + if(blockHeight >= PyrinConstants.Blake3ForkHeight) + { + string coinbaseBlockHash = KaspaConstants.CoinbaseBlockHash; + byte[] hashBytes = Encoding.UTF8.GetBytes(coinbaseBlockHash.PadRight(32, '\0')).Take(32).ToArray(); + this.blockHeaderHasher = new Blake3(hashBytes); + this.coinbaseHasher = new Blake3(); + this.shareHasher = new Blake3(); + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaClientFactory.cs b/src/Miningcore/Blockchain/Kaspa/KaspaClientFactory.cs new file mode 100644 index 000000000..0f5ef2957 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaClientFactory.cs @@ -0,0 +1,49 @@ +using System.Net.Http; +using Grpc.Core; +using Grpc.Net.Client; +using System.Net; +using System.Threading.Tasks; +using Miningcore.Blockchain.Kaspa.Configuration; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Mining; +using NLog; +using kaspaWalletd = Miningcore.Blockchain.Kaspa.KaspaWalletd; +using kaspad = Miningcore.Blockchain.Kaspa.Kaspad; + +namespace Miningcore.Blockchain.Kaspa; + +public static class KaspaClientFactory +{ + public static kaspad.KaspadRPC.KaspadRPCClient CreateKaspadRPCClient(IHttpClientFactory factory, DaemonEndpointConfig[] daemonEndpoints, string protobufDaemonRpcServiceName) + { + var daemonEndpoint = daemonEndpoints.First(); + + var baseUrl = new UriBuilder(daemonEndpoint.Ssl || daemonEndpoint.Http2 ? Uri.UriSchemeHttps : Uri.UriSchemeHttp, + daemonEndpoint.Host, daemonEndpoint.Port, daemonEndpoint.HttpPath); + + var channel = GrpcChannel.ForAddress(baseUrl.ToString(), new GrpcChannelOptions() + { + HttpClient = factory.CreateClient(), + DisposeHttpClient = true + }); + + return new kaspad.KaspadRPC.KaspadRPCClient(new kaspad.KaspadRPC(protobufDaemonRpcServiceName), channel); + } + + public static kaspaWalletd.KaspaWalletdRPC.KaspaWalletdRPCClient CreateKaspaWalletdRPCClient(IHttpClientFactory factory, DaemonEndpointConfig[] daemonEndpoints, string protobufWalletRpcServiceName) + { + var daemonEndpoint = daemonEndpoints.First(); + + var baseUrl = new UriBuilder(daemonEndpoint.Ssl || daemonEndpoint.Http2 ? Uri.UriSchemeHttps : Uri.UriSchemeHttp, + daemonEndpoint.Host, daemonEndpoint.Port, daemonEndpoint.HttpPath); + + var channel = GrpcChannel.ForAddress(baseUrl.ToString(), new GrpcChannelOptions() + { + HttpClient = factory.CreateClient(), + DisposeHttpClient = true + }); + + return new kaspaWalletd.KaspaWalletdRPC.KaspaWalletdRPCClient(new kaspaWalletd.KaspaWalletdRPC(protobufWalletRpcServiceName), channel); + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs b/src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs new file mode 100644 index 000000000..89d5252b1 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaConstants.cs @@ -0,0 +1,87 @@ +using System.Globalization; +using System.Numerics; +using System.Text.RegularExpressions; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Blockchain.Kaspa; + +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 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 const string CoinbaseBlockHash = "BlockHash"; + public const string CoinbaseProofOfWorkHash = "ProofOfWorkHash"; + public const string CoinbaseHeavyHash = "HeavyHash"; + + public const string ProtobufDaemonRpcServiceName = "protowire.RPC"; + public const string ProtobufWalletRpcServiceName = "kaspawalletd.kaspawalletd"; + + public const byte PubKeyAddrID = 0x00; + public const byte PubKeyECDSAAddrID = 0x01; + public const byte ScriptHashAddrID = 0x08; + public static readonly Dictionary KaspaAddressType = new Dictionary + { + { PubKeyAddrID, "Public Key Address" }, + { PubKeyECDSAAddrID, "Public Key ECDSA Address" }, + { ScriptHashAddrID, "Script Hash Address" }, + }; + public const int PublicKeySize = 32; + public const int PublicKeySizeECDSA = 33; + public const int Blake2bSize256 = 32; +} + +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 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 enum KaspaBech32Prefix +{ + Unknown = 0, + KaspaMain, + KaspaDev, + KaspaTest, + KaspaSim +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaExtraNonceProvider.cs b/src/Miningcore/Blockchain/Kaspa/KaspaExtraNonceProvider.cs new file mode 100644 index 000000000..e4dd8da7b --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaExtraNonceProvider.cs @@ -0,0 +1,8 @@ +namespace Miningcore.Blockchain.Kaspa; + +public class KaspaExtraNonceProvider : ExtraNonceProviderBase +{ + public KaspaExtraNonceProvider(string poolId, int size, byte? clusterInstanceId) : base(poolId, size, clusterInstanceId) + { + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs b/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs new file mode 100644 index 000000000..d21bb88c8 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs @@ -0,0 +1,373 @@ +using System; +using System.Globalization; +using System.Numerics; +using System.Collections.Concurrent; +using System.Text; +using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Extensions; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using NBitcoin; +using kaspad = Miningcore.Blockchain.Kaspa.Kaspad; + +namespace Miningcore.Blockchain.Kaspa; + +public class KaspaXoShiRo256PlusPlus +{ + private ulong[] s = new ulong[4]; + + public KaspaXoShiRo256PlusPlus(Span prePowHash) + { + Contract.Requires(prePowHash.Length >= 32); + + for (int i = 0; i < 4; i++) + { + s[i] = BitConverter.ToUInt64(prePowHash.Slice(i * 8, 8)); + } + } + + public ulong Uint64() + { + ulong result = RotateLeft64(this.s[0] + this.s[3], 23) + this.s[0]; + ulong t = this.s[1] << 17; + this.s[2] ^= this.s[0]; + this.s[3] ^= this.s[1]; + this.s[1] ^= this.s[2]; + this.s[0] ^= this.s[3]; + this.s[2] ^= t; + this.s[3] = RotateLeft64(this.s[3], 45); + return result; + } + + private static ulong RotateLeft64(ulong value, int offset) + { + return (value << offset) | (value >> (64 - offset)); + } + + private static ulong RotateRight64(ulong value, int offset) + { + return (value >> offset) | (value << (64 - offset)); + } +} + +public class KaspaJob +{ + protected IMasterClock clock; + public kaspad.RpcBlock BlockTemplate { get; private set; } + public double Difficulty { get; private set; } + public string JobId { get; protected set; } + public uint256 blockTargetValue { get; protected set; } + + private object[] jobParams; + private readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); + + protected IHashAlgorithm blockHeaderHasher = new Blake2b(Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseBlockHash)); + protected IHashAlgorithm coinbaseHasher = new CShake256(null, Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseProofOfWorkHash)); + protected IHashAlgorithm shareHasher = new CShake256(null, Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseHeavyHash)); + + protected bool RegisterSubmit(string nonce) + { + var key = new StringBuilder() + .Append(nonce) + .ToString(); + + return submissions.TryAdd(key, true); + } + + protected virtual ushort[][] GenerateMatrix(Span prePowHash) + { + ushort[][] matrix = new ushort[64][]; + for (int i = 0; i < 64; i++) + { + matrix[i] = new ushort[64]; + } + + var generator = new KaspaXoShiRo256PlusPlus(prePowHash); + while (true) + { + for (int i = 0; i < 64; i++) + { + for (int j = 0; j < 64; j += 16) + { + ulong val = generator.Uint64(); + for (int shift = 0; shift < 16; shift++) + { + matrix[i][j + shift] = (ushort)((val >> (4 * shift)) & 0x0F); + } + } + } + if(ComputeRank(matrix) == 64) + return matrix; + } + } + + protected virtual int ComputeRank(ushort[][] matrix) + { + double Eps = 0.000000001; + double[][] B = matrix.Select(row => row.Select(val => (double)val).ToArray()).ToArray(); + int rank = 0; + bool[] rowSelected = new bool[64]; + for (int i = 0; i < 64; i++) + { + int j; + for (j = 0; j < 64; j++) + { + if(!rowSelected[j] && Math.Abs(B[j][i]) > Eps) + break; + } + if(j != 64) + { + rank++; + rowSelected[j] = true; + double pivot = B[j][i]; + for (int p = i + 1; p < 64; p++) + { + B[j][p] /= pivot; + } + for (int k = 0; k < 64; k++) + { + if(k != j && Math.Abs(B[k][i]) > Eps) + { + for (int p = i + 1; p < 64; p++) + { + B[k][p] -= B[j][p] * B[k][i]; + } + } + } + } + } + return rank; + } + + protected virtual Span ComputeCoinbase(Span prePowHash, Span data) + { + ushort[][] matrix = GenerateMatrix(prePowHash); + ushort[] vector = new ushort[64]; + ushort[] product = new ushort[64]; + for (int i = 0; i < 32; i++) + { + vector[2 * i] = (ushort)(data[i] >> 4); + vector[2 * i + 1] = (ushort)(data[i] & 0x0F); + } + + for (int i = 0; i < 64; i++) + { + ushort sum = 0; + for (int j = 0; j < 64; j++) + { + sum += (ushort)(matrix[i][j] * vector[j]); + } + product[i] = (ushort)(sum >> 10); + } + + byte[] res = new byte[32]; + for (int i = 0; i < 32; i++) + { + res[i] = (byte)(data[i] ^ ((byte)(product[2 * i] << 4) | (byte)product[2 * i + 1])); + } + + return (Span) res; + } + + protected virtual Span SerializeCoinbase(Span prePowHash, long timestamp, ulong nonce) + { + Span hashBytes = stackalloc byte[32]; + + 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)); + + coinbaseHasher.Digest(stream.ToArray(), hashBytes); + + return (Span) hashBytes.ToArray(); + } + } + + protected virtual Span SerializeHeader(kaspad.RpcBlockHeader header, bool isPrePow = true, bool isLittleEndian = false) + { + ulong nonce = isPrePow ? 0 : header.Nonce; + long timestamp = isPrePow ? 0 : header.Timestamp; + Span hashBytes = stackalloc byte[32]; + //var blockHashBytes = Encoding.UTF8.GetBytes(KaspaConstants.CoinbaseBlockHash); + + using(var stream = new MemoryStream()) + { + var versionBytes = (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); + 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); + stream.Write(parentHashesBytes); + + foreach (var parentHash in parent.ParentHashes) + { + stream.Write(parentHash.HexToByteArray()); + } + } + + stream.Write(header.HashMerkleRoot.HexToByteArray()); + stream.Write(header.AcceptedIdMerkleRoot.HexToByteArray()); + stream.Write(header.UtxoCommitment.HexToByteArray()); + + var timestampBytes = (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); + stream.Write(bitsBytes); + var nonceBytes = (isLittleEndian) ? BitConverter.GetBytes(nonce).ReverseInPlace() : BitConverter.GetBytes(nonce); + stream.Write(nonceBytes); + var daaScoreBytes = (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); + 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); + stream.Write(blueWorkLengthBytes); + stream.Write(blueWorkBytes); + + stream.Write(header.PruningPoint.HexToByteArray()); + + blockHeaderHasher.Digest(stream.ToArray(), hashBytes); + + return (Span) hashBytes.ToArray(); + } + } + + protected virtual (string, ulong[]) SerializeJobParamsData(Span prePowHash, bool isLittleEndian = false) + { + 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); + + preHashStrings += slice.ToHexString().PadLeft(16, '0'); + preHashU64s[i] = BitConverter.ToUInt64(slice); + } + + return (preHashStrings, preHashU64s); + } + + 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); + + 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()) / KaspaConstants.ShareMultiplier} - [stratum: {context.Difficulty} - blockTemplate: {KaspaUtils.TargetToDifficulty(KaspaUtils.CompactToBig(BlockTemplate.Header.Bits)) / KaspaConstants.ShareMultiplier}] ||| AdjustShareDifficulty: {context.Difficulty * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash}"); + + // calc share-diff + var shareDiff = (double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) / KaspaConstants.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 / KaspaConstants.ShareMultiplier + }; + + if(isBlockCandidate) + { + var hashBytes = SerializeHeader(BlockTemplate.Header, false); + + result.IsBlockCandidate = true; + result.BlockHash = hashBytes.ToHexString(); + } + + return result; + } + + public object[] GetJobParams() + { + return jobParams; + } + + public virtual Share ProcessShare(StratumConnection worker, string nonce) + { + Contract.RequiresNonNull(worker); + Contract.Requires(!string.IsNullOrEmpty(nonce)); + + var context = worker.ContextAs(); + + // We don't need "0x" + nonce = (nonce.StartsWith("0x")) ? nonce.Substring(2) : nonce; + + // Add extranonce to nonce if enabled and submitted nonce is shorter than expected (16 - characters) + if (nonce.Length <= (KaspaConstants.NonceLength - context.ExtraNonce1.Length)) + { + nonce = context.ExtraNonce1.PadRight(KaspaConstants.NonceLength - context.ExtraNonce1.Length, '0') + nonce; + } + + // dupe check + if(!RegisterSubmit(nonce)) + throw new StratumException(StratumError.DuplicateShare, $"duplicate share"); + + return ProcessShareInternal(worker, nonce); + } + + public void Init(kaspad.RpcBlock blockTemplate, string jobId) + { + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(jobId); + + JobId = jobId; + var target = new Target(KaspaUtils.CompactToBig(blockTemplate.Header.Bits)); + Difficulty = KaspaUtils.TargetToDifficulty(target.ToBigInteger()) / KaspaConstants.ShareMultiplier; + 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/KaspaJobManager.cs b/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs new file mode 100644 index 000000000..5162717fc --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs @@ -0,0 +1,798 @@ +using System; +using static System.Array; +using System.Globalization; +using System.Net.Http; +using System.Numerics; +using System.Reactive; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using Autofac; +using Grpc.Core; +using Grpc.Net.Client; +using Miningcore.Blockchain.Kaspa.Configuration; +using Miningcore.Blockchain.Kaspa.Custom.Karlsencoin; +using Miningcore.Blockchain.Kaspa.Custom.Pyrin; +using NLog; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Notifications.Messages; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; +using kaspaWalletd = Miningcore.Blockchain.Kaspa.KaspaWalletd; +using kaspad = Miningcore.Blockchain.Kaspa.Kaspad; + +namespace Miningcore.Blockchain.Kaspa; + +public class KaspaJobManager : JobManagerBase +{ + public KaspaJobManager( + IComponentContext ctx, + IMessageBus messageBus, + IMasterClock clock, + IHttpClientFactory httpClientFactory, + IExtraNonceProvider extraNonceProvider) : + base(ctx, messageBus) + { + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(extraNonceProvider); + + this.clock = clock; + this.httpClientFactory = httpClientFactory; + this.extraNonceProvider = extraNonceProvider; + } + + private DaemonEndpointConfig[] daemonEndpoints; + private DaemonEndpointConfig[] walletDaemonEndpoints; + private KaspaCoinTemplate coin; + private IHttpClientFactory httpClientFactory; + 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; + private KaspaPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + protected int maxActiveJobs; + protected string extraData; + + protected IObservable KaspaSubscribeNewBlockTemplate(CancellationToken ct, object payload = null, + JsonSerializerSettings payloadJsonSerializerSettings = null) + { + return Observable.Defer(() => Observable.Create(obs => + { + var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); + + Task.Run(async () => + { + using(cts) + { + retry: + try + { + // we need a stream to communicate with Kaspad + var streamNotifyNewBlockTemplate = rpc.MessageStream(null, null, cts.Token); + + var requestNotifyNewBlockTemplate = new kaspad.KaspadMessage(); + requestNotifyNewBlockTemplate.NotifyNewBlockTemplateRequest = new kaspad.NotifyNewBlockTemplateRequestMessage(); + logger.Debug(() => $"Sending NotifyNewBlockTemplateRequest"); + await streamNotifyNewBlockTemplate.RequestStream.WriteAsync(requestNotifyNewBlockTemplate); + while (!cts.IsCancellationRequested && await streamNotifyNewBlockTemplate.ResponseStream.MoveNext()) + { + if(streamNotifyNewBlockTemplate.ResponseStream.Current.NewBlockTemplateNotification != null) + { + logger.Debug(() => $"New job received :D"); + + var streamBlockTemplate = rpc.MessageStream(null, null, cts.Token); + var requestBlockTemplate = new kaspad.KaspadMessage(); + requestBlockTemplate.GetBlockTemplateRequest = new kaspad.GetBlockTemplateRequestMessage + { + PayAddress = poolConfig.Address, + ExtraData = extraData, + }; + await streamBlockTemplate.RequestStream.WriteAsync(requestBlockTemplate); + await foreach (var responseBlockTemplate in streamBlockTemplate.ResponseStream.ReadAllAsync()) + { + if(string.IsNullOrEmpty(responseBlockTemplate.GetBlockTemplateResponse.Error?.Message)) + { + logger.Debug(() => $"DaaScore (BlockHeight): {responseBlockTemplate.GetBlockTemplateResponse.Block.Header.DaaScore}"); + + // publish + //logger.Debug(() => $"Publishing..."); + obs.OnNext(responseBlockTemplate.GetBlockTemplateResponse.Block); + } + else + logger.Warn(() => responseBlockTemplate.GetBlockTemplateResponse.Error?.Message); + + break; + } + await streamBlockTemplate.RequestStream.CompleteAsync(); + } + } + logger.Debug(() => $"No more data received. Bye!"); + await streamNotifyNewBlockTemplate.RequestStream.CompleteAsync(); + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while streaming kaspad \"NewBlockTemplate\" notifications. Reconnecting in 10s"); + } + + if(!cts.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromSeconds(10), cts.Token); + goto retry; + } + } + }, cts.Token); + + return Disposable.Create(() => { cts.Cancel(); }); + })); + } + + private void SetupJobUpdates(CancellationToken ct) + { + var blockFound = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); + + var triggers = new List> + { + blockFound.Select(_ => (JobRefreshBy.BlockFound, (kaspad.RpcBlock) null)) + }; + + // Listen to kaspad "NewBlockTemplate" notifications + var getWorkKaspad = KaspaSubscribeNewBlockTemplate(ct) + .Publish() + .RefCount(); + + triggers.Add(getWorkKaspad + .Select(blockTemplate => (JobRefreshBy.BlockTemplateStream, blockTemplate)) + .Publish() + .RefCount()); + + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (kaspad.RpcBlock) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + + Jobs = triggers.Merge() + .Select(x => Observable.FromAsync(() => UpdateJob(ct, x.Via, x.Data))) + .Concat() + .Where(x => x) + .Do(x => + { + if(x) + hasInitialBlockTemplate = true; + }) + .Select(x => GetJobParamsForStratum()) + .Publish() + .RefCount(); + } + + private KaspaJob CreateJob(long blockHeight) + { + switch(coin.Symbol) + { + case "KLS": + return new KarlsencoinJob(); + + case "PYI": + if(blockHeight >= PyrinConstants.Blake3ForkHeight) + logger.Debug(() => $"blake3HardFork activated"); + + return new PyrinJob(blockHeight); + } + + return new KaspaJob(); + } + + private async Task UpdateJob(CancellationToken ct, string via = null, kaspad.RpcBlock blockTemplate = null) + { + var cts = CancellationTokenSource.CreateLinkedTokenSource(ct); + + return await Task.Run(() => + { + using(cts) + { + try + { + if(blockTemplate == null) + return false; + + var job = currentJob; + + var isNew = (job == null || job.BlockTemplate?.Header.DaaScore < blockTemplate.Header.DaaScore); + + if(isNew) + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Header.DaaScore, poolConfig.Template); + + if(isNew) + { + job = CreateJob((long) blockTemplate.Header.DaaScore); + + job.Init(blockTemplate, NextJobId()); + + lock(jobLock) + { + validJobs.Insert(0, job); + + // trim active jobs + while(validJobs.Count > maxActiveJobs) + validJobs.RemoveAt(validJobs.Count - 1); + } + + logger.Debug(() => $"blockTargetValue: {job.blockTargetValue}"); + logger.Debug(() => $"Difficulty: {job.Difficulty}"); + + if(via != null) + logger.Info(() => $"Detected new block {job.BlockTemplate.Header.DaaScore} [{via}]"); + else + logger.Info(() => $"Detected new block {job.BlockTemplate.Header.DaaScore}"); + + // update stats + if (job.BlockTemplate.Header.DaaScore > BlockchainStats.BlockHeight) + { + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = job.BlockTemplate.Header.DaaScore; + BlockchainStats.NetworkDifficulty = job.Difficulty; + } + + currentJob = job; + } + else + { + if(via != null) + logger.Debug(() => $"Template update {job.BlockTemplate.Header.DaaScore}"); + else + logger.Debug(() => $"Template update {job.BlockTemplate.Header.DaaScore}"); + } + + return isNew; + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while updating new job"); + } + + return false; + } + }, cts.Token); + } + + private async Task UpdateNetworkStatsAsync(CancellationToken ct) + { + try + { + // update stats + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.EstimateNetworkHashesPerSecondRequest = new kaspad.EstimateNetworkHashesPerSecondRequestMessage + { + WindowSize = 1000, + }; + await stream.RequestStream.WriteAsync(request); + await foreach (var infoHashrate in stream.ResponseStream.ReadAllAsync()) + { + if(string.IsNullOrEmpty(infoHashrate.EstimateNetworkHashesPerSecondResponse.Error?.Message)) + BlockchainStats.NetworkHashrate = (double) infoHashrate.EstimateNetworkHashesPerSecondResponse.NetworkHashesPerSecond; + + break; + } + await stream.RequestStream.CompleteAsync(); + + // we need a stream to communicate with Kaspad + stream = rpc.MessageStream(null, null, ct); + + request = new kaspad.KaspadMessage(); + request.GetConnectedPeerInfoRequest = new kaspad.GetConnectedPeerInfoRequestMessage(); + await stream.RequestStream.WriteAsync(request); + await foreach (var info in stream.ResponseStream.ReadAllAsync()) + { + if(string.IsNullOrEmpty(info.GetConnectedPeerInfoResponse.Error?.Message)) + BlockchainStats.ConnectedPeers = info.GetConnectedPeerInfoResponse.Infos.Count; + + break; + } + await stream.RequestStream.CompleteAsync(); + } + + catch(Exception ex) + { + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while updating network stats"); + } + } + + private async Task ShowDaemonSyncProgressAsync(CancellationToken ct) + { + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.GetInfoRequest = new kaspad.GetInfoRequestMessage(); + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> logger.Debug(ex)); + await foreach (var info in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(info.GetInfoResponse.Error?.Message)) + logger.Debug(info.GetInfoResponse.Error?.Message); + + if(info.GetInfoResponse.IsSynced != true && info.GetInfoResponse.IsUtxoIndexed != true) + logger.Info(() => $"Daemon is downloading headers ..."); + + break; + } + await stream.RequestStream.CompleteAsync(); + } + + private async Task SubmitBlockAsync(CancellationToken ct, kaspad.RpcBlock block, object payload = null, + JsonSerializerSettings payloadJsonSerializerSettings = null) + { + Contract.RequiresNonNull(block); + + bool succeed = false; + + try + { + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.SubmitBlockRequest = new kaspad.SubmitBlockRequestMessage + { + Block = block, + AllowNonDAABlocks = false, + }; + await stream.RequestStream.WriteAsync(request); + await foreach (var response in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(response.SubmitBlockResponse.Error?.Message)) + { + // We lost that battle + logger.Warn(() => $"Block submission failed: {response.SubmitBlockResponse.Error?.Message} [{response.SubmitBlockResponse?.RejectReason.ToString()}]"); + messageBus.SendMessage(new AdminNotification("Block submission failed", $"Pool {poolConfig.Id}: {response.SubmitBlockResponse.Error?.Message} [{response.SubmitBlockResponse?.RejectReason.ToString()}]")); + } + else + succeed = true; + + break; + } + await stream.RequestStream.CompleteAsync(); + } + + catch(Exception ex) + { + // We lost that battle + logger.Error(() => $"{ex.GetType().Name} '{ex.Message}' while submitting block"); + messageBus.SendMessage(new AdminNotification("Block submission failed", $"Pool {poolConfig.Id} failed to submit block")); + } + + return succeed; + } + + #region API-Surface + + public IObservable Jobs { get; private set; } + public BlockchainStats BlockchainStats { get; } = new(); + public string Network => network; + + public KaspaCoinTemplate Coin => coin; + + 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, + KaspaConstants.ExtranoncePlaceHolderLength - extraNonce1Size, + }; + + return responseData; + } + + public int GetExtraNonce1Size() + { + return extraPoolConfig?.ExtraNonce1Size ?? 2; + } + + 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(); + + var jobId = submitParams[1] as string; + var nonce = submitParams[2] as string; + + KaspaJob job; + + lock(jobLock) + { + job = validJobs.FirstOrDefault(x => x.JobId == 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}]"); + + var acceptResponse = await SubmitBlockAsync(ct, job.BlockTemplate); + + // 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 bool ValidateIsLargeJob(string userAgent) + { + if(string.IsNullOrEmpty(userAgent)) + return false; + + if(ValidateIsBzMiner(userAgent)) + return true; + + if(ValidateIsIceRiverMiner(userAgent)) + return true; + + return false; + } + + public bool ValidateIsBzMiner(string userAgent) + { + if(string.IsNullOrEmpty(userAgent)) + return false; + + // Find matches + MatchCollection matchesUserAgentBzMiner = KaspaConstants.RegexUserAgentBzMiner.Matches(userAgent); + return (matchesUserAgentBzMiner.Count > 0); + } + + public bool ValidateIsGodMiner(string userAgent) + { + if(string.IsNullOrEmpty(userAgent)) + return false; + + // Find matches + MatchCollection matchesUserAgentGodMiner = KaspaConstants.RegexUserAgentGodMiner.Matches(userAgent); + return (matchesUserAgentGodMiner.Count > 0); + } + + public bool ValidateIsIceRiverMiner(string userAgent) + { + if(string.IsNullOrEmpty(userAgent)) + return false; + + // Find matches + MatchCollection matchesUserAgentIceRiverMiner = KaspaConstants.RegexUserAgentIceRiverMiner.Matches(userAgent); + return (matchesUserAgentIceRiverMiner.Count > 0); + } + + #endregion // API-Surface + + #region Overrides + + 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); + + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.GetCurrentNetworkRequest = new kaspad.GetCurrentNetworkRequestMessage(); + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> throw new PoolStartupException($"Error writing a request in the communication stream '{ex.GetType().Name}' : {ex}", poolConfig.Id)); + await foreach (var currentNetwork in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(currentNetwork.GetCurrentNetworkResponse.Error?.Message)) + throw new PoolStartupException($"Daemon reports: {currentNetwork.GetCurrentNetworkResponse.Error?.Message}", poolConfig.Id); + + network = currentNetwork.GetCurrentNetworkResponse.CurrentNetwork; + break; + } + await stream.RequestStream.CompleteAsync(); + + var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(poolConfig.Address, network, coin.Symbol); + 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"; + + // we need a stream to communicate with Kaspad + stream = rpc.MessageStream(null, null, ct); + + request = new kaspad.KaspadMessage(); + request.GetInfoRequest = new kaspad.GetInfoRequestMessage(); + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> throw new PoolStartupException($"Error writing a request in the communication stream '{ex.GetType().Name}' : {ex}", poolConfig.Id)); + await foreach (var info in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(info.GetInfoResponse.Error?.Message)) + throw new PoolStartupException($"Daemon reports: {info.GetInfoResponse.Error?.Message}", poolConfig.Id); + + if(info.GetInfoResponse.IsUtxoIndexed != true) + throw new PoolStartupException("UTXO index is disabled", poolConfig.Id); + + extraData = (string) info.GetInfoResponse.ServerVersion + (!string.IsNullOrEmpty(extraData) ? "." + extraData : ""); + break; + } + await stream.RequestStream.CompleteAsync(); + + // Payment-processing setup + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // 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)); + + 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 + Observable.Interval(TimeSpan.FromMinutes(1)) + .Select(via => Observable.FromAsync(() => + Guard(()=> UpdateNetworkStatsAsync(ct), + ex=> logger.Error(ex)))) + .Concat() + .Subscribe(); + + SetupJobUpdates(ct); + } + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + coin = pc.Template.As(); + + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + + maxActiveJobs = extraPoolConfig?.MaxActiveJobs ?? 8; + 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 + walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == KaspaConstants.WalletDaemonCategory) + .ToArray(); + + if(walletDaemonEndpoints.Length == 0) + throw new PoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for kaspa-pools require an additional entry of category 'wallet' pointing to the wallet daemon)", pc.Id); + } + + base.Configure(pc, cc); + } + + protected override void ConfigureDaemons() + { + logger.Debug(() => $"ProtobufDaemonRpcServiceName: {extraPoolConfig?.ProtobufDaemonRpcServiceName ?? KaspaConstants.ProtobufDaemonRpcServiceName}"); + + rpc = KaspaClientFactory.CreateKaspadRPCClient(httpClientFactory, daemonEndpoints, extraPoolConfig?.ProtobufDaemonRpcServiceName ?? KaspaConstants.ProtobufDaemonRpcServiceName); + + // Payment-processing setup + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + logger.Debug(() => $"ProtobufWalletRpcServiceName: {extraPoolConfig?.ProtobufWalletRpcServiceName ?? KaspaConstants.ProtobufWalletRpcServiceName}"); + + walletRpc = KaspaClientFactory.CreateKaspaWalletdRPCClient(httpClientFactory, walletDaemonEndpoints, extraPoolConfig?.ProtobufWalletRpcServiceName ?? KaspaConstants.ProtobufWalletRpcServiceName); + } + } + + protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) + { + // Payment-processing setup + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // 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=> logger.Debug(ex)); + + if(walletAddresses == null) + return false; + } + + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.GetInfoRequest = new kaspad.GetInfoRequestMessage(); + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> logger.Debug(ex)); + bool areDaemonsHealthy = false; + await foreach (var info in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(info.GetInfoResponse.Error?.Message)) + { + logger.Debug(info.GetInfoResponse.Error?.Message); + return false; + } + + if(info.GetInfoResponse.IsUtxoIndexed != true) + throw new PoolStartupException("UTXO index is disabled", poolConfig.Id); + + areDaemonsHealthy = true; + break; + } + await stream.RequestStream.CompleteAsync(); + + return areDaemonsHealthy; + } + + protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) + { + // Payment-processing setup + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // 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=> logger.Debug(ex)); + + if(walletAddresses == null) + return false; + } + + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.GetConnectedPeerInfoRequest = new kaspad.GetConnectedPeerInfoRequestMessage(); + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> logger.Debug(ex)); + int totalPeers = 0; + await foreach (var info in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(info.GetConnectedPeerInfoResponse.Error?.Message)) + { + logger.Debug(info.GetConnectedPeerInfoResponse.Error?.Message); + return false; + } + else + totalPeers = info.GetConnectedPeerInfoResponse.Infos.Count; + + break; + } + await stream.RequestStream.CompleteAsync(); + + return totalPeers > 0; + } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + var syncPendingNotificationShown = false; + + do + { + var isSynched = false; + + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.GetInfoRequest = new kaspad.GetInfoRequestMessage(); + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> logger.Debug(ex)); + await foreach (var info in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(info.GetInfoResponse.Error?.Message)) + logger.Debug(info.GetInfoResponse.Error?.Message); + + isSynched = (info.GetInfoResponse.IsSynced == true && info.GetInfoResponse.IsUtxoIndexed == true); + break; + } + await stream.RequestStream.CompleteAsync(); + + if(isSynched) + { + logger.Info(() => "Daemon is synced 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)); + } + + 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 new file mode 100644 index 000000000..d24c01aeb --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaPayoutHandler.cs @@ -0,0 +1,449 @@ +using System; +using System.Net.Http; +using Autofac; +using AutoMapper; +using Grpc.Core; +using Grpc.Net.Client; +using Miningcore.Blockchain.Kaspa.Configuration; +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.Time; +using Miningcore.Util; +using Block = Miningcore.Persistence.Model.Block; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; +using kaspaWalletd = Miningcore.Blockchain.Kaspa.KaspaWalletd; +using kaspad = Miningcore.Blockchain.Kaspa.Kaspad; + +namespace Miningcore.Blockchain.Kaspa; + +[CoinFamily(CoinFamily.Kaspa)] +public class KaspaPayoutHandler : PayoutHandlerBase, + IPayoutHandler +{ + public KaspaPayoutHandler( + 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; + protected kaspad.KaspadRPC.KaspadRPCClient rpc; + protected kaspaWalletd.KaspaWalletdRPC.KaspaWalletdRPCClient walletRpc; + private string network; + private KaspaPoolConfigExtra extraPoolConfig; + private KaspaPaymentProcessingConfigExtra extraPoolPaymentProcessingConfig; + + protected override string LogCategory => "Kaspa Payout Handler"; + + #region IPayoutHandler + + public virtual async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, CancellationToken ct) + { + Contract.RequiresNonNull(pc); + + poolConfig = pc; + clusterConfig = cc; + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + extraPoolPaymentProcessingConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + + logger = LogUtil.GetPoolScopedLogger(typeof(KaspaPayoutHandler), pc); + + // extract standard daemon endpoints + var daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .ToArray(); + + // extract wallet daemon endpoints + var walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == KaspaConstants.WalletDaemonCategory) + .ToArray(); + + if(walletDaemonEndpoints.Length == 0) + throw new PaymentException("Wallet-RPC daemon is not configured (Daemon configuration for kaspa-pools require an additional entry of category 'wallet' pointing to the wallet daemon)"); + + rpc = KaspaClientFactory.CreateKaspadRPCClient(httpClientFactory, daemonEndpoints, extraPoolConfig?.ProtobufDaemonRpcServiceName ?? KaspaConstants.ProtobufDaemonRpcServiceName); + walletRpc = KaspaClientFactory.CreateKaspaWalletdRPCClient(httpClientFactory, walletDaemonEndpoints, extraPoolConfig?.ProtobufWalletRpcServiceName ?? KaspaConstants.ProtobufWalletRpcServiceName); + + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.GetCurrentNetworkRequest = new kaspad.GetCurrentNetworkRequestMessage(); + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> throw new PaymentException($"Error writing a request in the communication stream '{ex.GetType().Name}' : {ex}")); + await foreach (var currentNetwork in stream.ResponseStream.ReadAllAsync()) + { + if(!string.IsNullOrEmpty(currentNetwork.GetCurrentNetworkResponse.Error?.Message)) + throw new PaymentException($"Daemon reports: {currentNetwork.GetCurrentNetworkResponse.Error?.Message}"); + + network = currentNetwork.GetCurrentNetworkResponse.CurrentNetwork; + break; + } + await stream.RequestStream.CompleteAsync(); + } + + public virtual async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, CancellationToken ct) + { + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(blocks); + + if(blocks.Length == 0) + return blocks; + + var coin = poolConfig.Template.As(); + var pageSize = 100; + var pageCount = (int) Math.Ceiling(blocks.Length / (double) pageSize); + var result = new List(); + int minConfirmations = extraPoolPaymentProcessingConfig?.MinimumConfirmations ?? (network == "mainnet" ? 120 : 110); + + 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]; + + // we need a stream to communicate with Kaspad + var stream = rpc.MessageStream(null, null, ct); + + var request = new kaspad.KaspadMessage(); + request.GetBlockRequest = new kaspad.GetBlockRequestMessage + { + Hash = (string) block.Hash, + IncludeTransactions = true, + }; + await Guard(() => stream.RequestStream.WriteAsync(request), + ex=> logger.Debug(ex)); + await foreach (var blockInfo in stream.ResponseStream.ReadAllAsync()) + { + // We lost that battle + if(!string.IsNullOrEmpty(blockInfo.GetBlockResponse.Error?.Message)) + { + result.Add(block); + + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} classified as orphaned because it's not the chain"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + else + { + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} uses a custom minimum confirmations calculation [{minConfirmations}]"); + + var streamConfirmations = rpc.MessageStream(null, null, ct); + var requestConfirmations = new kaspad.KaspadMessage(); + requestConfirmations.GetBlocksRequest = new kaspad.GetBlocksRequestMessage + { + LowHash = (string) block.Hash, + IncludeBlocks = false, + IncludeTransactions = false, + }; + await Guard(() => streamConfirmations.RequestStream.WriteAsync(requestConfirmations), + ex=> logger.Debug(ex)); + await foreach (var responseConfirmations in streamConfirmations.ResponseStream.ReadAllAsync()) + { + block.ConfirmationProgress = Math.Min(1.0d, (double) responseConfirmations.GetBlocksResponse.BlockHashes.Count / minConfirmations); + break; + } + await streamConfirmations.RequestStream.CompleteAsync(); + + result.Add(block); + + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + // matured and spendable? + if(block.ConfirmationProgress >= 1) + { + + // KASPA block reward calculation is a complete nightmare: https://wiki.kaspa.org/en/merging-and-rewards + decimal blockReward = 0.0m; + + var childrenProvideRewards = false; + + // First: We need the parse the children(s) related to the block reward, because in GhostDAG the child(s) reward(s) the parent + foreach(var childrenHash in blockInfo.GetBlockResponse.Block.VerboseData.ChildrenHashes) + { + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} contains child: {childrenHash}"); + + var streamChildren = rpc.MessageStream(); + var requestChildren = new kaspad.KaspadMessage(); + requestChildren.GetBlockRequest = new kaspad.GetBlockRequestMessage + { + Hash = childrenHash, + IncludeTransactions = true, + }; + await streamChildren.RequestStream.WriteAsync(requestChildren); + await Guard(() => streamChildren.RequestStream.WriteAsync(requestChildren), + ex=> logger.Debug(ex)); + await foreach (var responseChildren in streamChildren.ResponseStream.ReadAllAsync()) + { + // we only need the transaction(s) related to the block reward + var childrenBlockRewardTransactions = responseChildren.GetBlockResponse.Block.Transactions + .Where(x => x.Inputs.Count < 1) + .ToList(); + + if(childrenBlockRewardTransactions.Count > 0) + { + // We need to know if our initial blockHah is in the redMerges + var mergeSetRedsHashess = responseChildren.GetBlockResponse.Block.VerboseData.MergeSetRedsHashes + .Where(x => x.Contains((string) block.Hash)) + .ToList(); + + // We need to know if our initial blockHah is in the redMerges + var mergeSetBluesHashes = responseChildren.GetBlockResponse.Block.VerboseData.MergeSetBluesHashes + .Where(x => x.Contains((string) block.Hash)) + .ToList(); + + if(mergeSetRedsHashess.Count > 0) + { + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} - block child {responseChildren.GetBlockResponse.Block.Header.DaaScore} [{childrenHash}] provides {FormatAmount(0.0m)}"); + } + else if(mergeSetBluesHashes.Count > 0 && responseChildren.GetBlockResponse.Block.VerboseData.IsChainBlock) + { + var childrenPosition = responseChildren.GetBlockResponse.Block.VerboseData.MergeSetBluesHashes.IndexOf((string) block.Hash); + + // Are those rewards going to the pool wallet? + if(childrenBlockRewardTransactions.First().Outputs[childrenPosition].VerboseData.ScriptPublicKeyAddress == poolConfig.Address) + { + childrenProvideRewards = true; + + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} - block child {responseChildren.GetBlockResponse.Block.Header.DaaScore} [{childrenHash}] provides {FormatAmount((decimal) (childrenBlockRewardTransactions.First().Outputs[childrenPosition].Amount / KaspaConstants.SmallestUnit))} => {coin.Symbol} address: {childrenBlockRewardTransactions.First().Outputs[childrenPosition].VerboseData.ScriptPublicKeyAddress} [{poolConfig.Address}]"); + blockReward += (decimal) (childrenBlockRewardTransactions.First().Outputs[childrenPosition].Amount / KaspaConstants.SmallestUnit); + } + else + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} - block child {responseChildren.GetBlockResponse.Block.Header.DaaScore} [{childrenHash}] provides {FormatAmount(0.0m)}"); + + } + else + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} - block child {responseChildren.GetBlockResponse.Block.Header.DaaScore} [{childrenHash}] provides {FormatAmount(0.0m)}"); + } + else + logger.Warn(() => $"[{LogCategory}] Block {block.BlockHeight} - block child {responseChildren.GetBlockResponse.Block.Header.DaaScore} [{childrenHash}] does not contain transaction(s) related to the block reward, block maybe will not be unlocked :'("); + + break; + } + await streamChildren.RequestStream.CompleteAsync(); + } + + // Hold on, we still have one more thing to check + if(blockInfo.GetBlockResponse.Block.VerboseData.IsChainBlock && childrenProvideRewards == false) + { + // we only need the transaction(s) related to the block reward + var blockRewardTransactions = blockInfo.GetBlockResponse.Block.Transactions + .Where(x => x.Inputs.Count < 1) + .ToList(); + + if(blockRewardTransactions.Count > 0) + { + // We only need the transactions for the pool wallet + var amounts = blockRewardTransactions.First().Outputs + .Where(x => x.VerboseData.ScriptPublicKeyAddress == poolConfig.Address) + .ToList(); + + if(amounts.Count > 0) + { + var totalAmount = amounts + .Sum(x => (x.Amount / KaspaConstants.SmallestUnit)); + + logger.Debug(() => $"[{LogCategory}] Block {block.BlockHeight} contains: {FormatAmount(totalAmount)}"); + blockReward += (decimal) totalAmount; + } + else + logger.Warn(() => $"[{LogCategory}] Block {block.BlockHeight} coinbase transaction(s) provide(s) {FormatAmount(0.0m)}"); + } + else + logger.Warn(() => $"[{LogCategory}] Block {block.BlockHeight} does not contain transaction(s) related to the block reward, block maybe will not be unlocked :'("); + } + + if(blockReward > 0) + { + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + + // reset block reward + block.Reward = blockReward; + + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + else + { + logger.Warn(() => $"[{LogCategory}] Block {block.BlockHeight} does not receive any block reward :'("); + + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + logger.Info(() => $"[{LogCategory}] Block {block.BlockHeight} classified as orphaned because no reward has been found"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + } + } + break; + } + await stream.RequestStream.CompleteAsync(); + } + } + + 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(balances.Sum(x => x.Amount))} 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); + + if(errorKaspaAddressUtility != null) + logger.Warn(()=> $"[{LogCategory}] Address {pair.Key} is not valid : {errorKaspaAddressUtility}"); + } + + var callGetBalance = walletRpc.GetBalanceAsync(new kaspaWalletd.GetBalanceRequest()); + var walletBalances = await Guard(() => callGetBalance.ResponseAsync, + ex=> logger.Debug(ex)); + + var walletBalancePending = (decimal) (walletBalances?.Pending == null ? 0 : walletBalances?.Pending) / KaspaConstants.SmallestUnit; + var walletBalanceAvailable = (decimal) (walletBalances?.Available == null ? 0 : walletBalances?.Available) / KaspaConstants.SmallestUnit; + + logger.Info(() => $"[{LogCategory}] Current wallet balance - Total: [{FormatAmount(walletBalancePending + walletBalanceAvailable)}] - Pending: [{FormatAmount(walletBalancePending)}] - Available: [{FormatAmount(walletBalanceAvailable)}]"); + + // bail if balance does not satisfy payments + if(walletBalanceAvailable < balancesTotal) + { + 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 + { + MaxDegreeOfParallelism = extraPoolPaymentProcessingConfig?.MaxDegreeOfParallelPayouts ?? 2, + CancellationToken = ct + }; + + await Parallel.ForEachAsync(amounts, parallelOptions, async (x, _ct) => + { + var (address, amount) = x; + + await Guard(async () => + { + // 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, + IsSendAll = false, + }); + var sendTransaction = await Guard(() => callSend.ResponseAsync, + ex=> throw new PaymentException($"[{transferId}] kaspawalletd returned error: {ex}")); + + // check result + var txId = sendTransaction.TxIDs.First(); + + if(string.IsNullOrEmpty(txId)) + throw new Exception($"[{transferId}] kaspawalletd did not return a transaction id!"); + else + logger.Info(() => $"[{LogCategory}] [{transferId}] Payment transaction id: {txId}"); + + successBalances.Add(new Balance + { + PoolId = poolConfig.Id, + Address = address, + Amount = amount, + }, txId); + }, 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 override double AdjustShareDifficulty(double difficulty) + { + return difficulty * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + } + + public double AdjustBlockEffort(double effort) + { + return effort * KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + } + + #endregion // IPayoutHandler + + private class PaymentException : Exception + { + public PaymentException(string msg) : base(msg) + { + } + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaPool.cs b/src/Miningcore/Blockchain/Kaspa/KaspaPool.cs new file mode 100644 index 000000000..3bcfa866d --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaPool.cs @@ -0,0 +1,431 @@ +using System.Numerics; +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.Kaspa.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 Miningcore.Util; +using Newtonsoft.Json; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Kaspa; + +[CoinFamily(CoinFamily.Kaspa)] +public class KaspaPool : PoolBase +{ + public KaspaPool(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) + { + } + + protected object[] currentJobParams; + protected KaspaJobManager manager; + private KaspaPoolConfigExtra extraPoolConfig; + private KaspaCoinTemplate coin; + + protected virtual async Task OnSubscribeAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + // setup worker context + var requestParams = request.ParamsAs(); + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); + context.IsLargeJob = manager.ValidateIsLargeJob(context.UserAgent); + + if(manager.ValidateIsGodMiner(context.UserAgent)) + { + var data = new object[] + { + null, + } + .Concat(manager.GetSubscriberData(connection)) + .ToArray(); + + await connection.RespondAsync(data, request.Id); + } + + else + { + var data = new object[] + { + true, + "KaspaStratum/1.0.0", + }; + + await connection.RespondAsync(data, request.Id); + await connection.NotifyAsync(KaspaStratumMethods.SetExtraNonce, manager.GetSubscriberData(connection)); + } + + context.IsSubscribed = true; + } + + 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(); + + // setup worker context + context.IsSubscribed = true; + + 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 + var (kaspaAddressUtility, errorKaspaAddressUtility) = KaspaUtils.ValidateAddress(minerName, manager.Network, coin.Symbol); + if (errorKaspaAddressUtility != null) + logger.Warn(() => $"[{connection.ConnectionId}] Unauthorized worker: {errorKaspaAddressUtility}"); + else + { + context.IsAuthorized = true; + logger.Info(() => $"[{connection.ConnectionId}] worker: {minerName} => {KaspaConstants.KaspaAddressType[kaspaAddressUtility.KaspaAddress.Version()]}"); + } + + context.Miner = minerName; + context.Worker = workerName; + + if(context.IsAuthorized) + { + // respond + await connection.RespondAsync(context.IsAuthorized, request.Id); + + // log association + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {workerValue}"); + + // 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}"); + } + + // send intial job + await SendJob(connection, context, currentJobParams); + } + + 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); + } + } + } + + 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); + await connection.RespondAsync(true, request.Id); + + // 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 * KaspaConstants.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 {jobParams[0]}"); + + await Guard(() => ForEachMinerAsync(async (connection, ct) => + { + var context = connection.ContextAs(); + + await SendJob(connection, context, currentJobParams); + })); + } + + private async Task SendJob(StratumConnection connection, KaspaWorkerContext context, object[] jobParams) + { + object[] jobParamsActual; + if(context.IsLargeJob) + { + jobParamsActual = new object[] { + jobParams[0], + jobParams[1], + }; + } + else + { + jobParamsActual = new object[] { + jobParams[0], + jobParams[2], + jobParams[3], + }; + } + + // send difficulty + await connection.NotifyAsync(KaspaStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + // send job + await connection.NotifyAsync(KaspaStratumMethods.MiningNotify, jobParamsActual); + } + + public override double HashrateFromShares(double shares, double interval) + { + var multiplier = KaspaConstants.Pow2xDiff1TargetNumZero * (double) KaspaConstants.MinHash; + var result = shares * multiplier / interval; + + return result; + } + + public override double ShareMultiplier => KaspaConstants.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 ?? 2; + + manager = ctx.Resolve( + new TypedParameter(typeof(IExtraNonceProvider), new KaspaExtraNonceProvider(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 KaspaWorkerContext(); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + try + { + switch(request.Method) + { + case KaspaStratumMethods.Subscribe: + await OnSubscribeAsync(connection, tsRequest, ct); + break; + + case KaspaStratumMethods.ExtraNonceSubscribe: + var context = connection.ContextAs(); + + var data = new object[] + { + context.ExtraNonce1, + KaspaConstants.ExtranoncePlaceHolderLength - manager.GetExtraNonce1Size(), + }; + + await connection.NotifyAsync(KaspaStratumMethods.SetExtraNonce, data); + break; + + case KaspaStratumMethods.Authorize: + await OnAuthorizeAsync(connection, tsRequest, ct); + break; + + case KaspaStratumMethods.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 GetNicehashStaticMinDiff(WorkerContextBase context, string coinName, string algoName) + { + var result = await base.GetNicehashStaticMinDiff(context, coinName, algoName); + + // adjust value to fit with our target value calculation + if(result.HasValue) + result = result.Value / uint.MaxValue; + + return result; + } + + protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) + { + await base.OnVarDiffUpdateAsync(connection, newDiff, ct); + + var context = connection.ContextAs(); + + if(context.ApplyPendingDifficulty()) + { + // send job + await SendJob(connection, context, currentJobParams); + } + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaStratumMethods.cs b/src/Miningcore/Blockchain/Kaspa/KaspaStratumMethods.cs new file mode 100644 index 000000000..d47626fc1 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaStratumMethods.cs @@ -0,0 +1,39 @@ +namespace Miningcore.Blockchain.Kaspa; + +public class KaspaStratumMethods +{ + /// + /// 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 ExtraNonceSubscribe = "mining.extranonce.subscribe"; + + /// + /// Used to subscribe to work from a server, required before all other communication. + /// + public const string SetExtraNonce = "set_extranonce"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs b/src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs new file mode 100644 index 000000000..2e988ad64 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaUtils.cs @@ -0,0 +1,668 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Miningcore.Crypto; +using Miningcore.Crypto.Hashing.Algorithms; +using Miningcore.Util; +using NBitcoin; + +namespace Miningcore.Blockchain.Kaspa; + +public static class KaspaUtils +{ + public static (KaspaAddressUtility, Exception) ValidateAddress(string address, string network, string coinSymbol = "KAS") + { + if(string.IsNullOrEmpty(address)) + return (null, new ArgumentException($"Empty address...")); + + KaspaBech32Prefix networkBech32Prefix; + + switch(network.ToLower()) + { + case "devnet": + networkBech32Prefix = KaspaBech32Prefix.KaspaDev; + + break; + case "simnet": + networkBech32Prefix = KaspaBech32Prefix.KaspaSim; + + break; + case "testnet": + networkBech32Prefix = KaspaBech32Prefix.KaspaTest; + + break; + default: + networkBech32Prefix = KaspaBech32Prefix.KaspaMain; + + break; + } + + try + { + var kaspaAddressUtility = new KaspaAddressUtility(coinSymbol); + kaspaAddressUtility.DecodeAddress(address, networkBech32Prefix); + + return (kaspaAddressUtility, null); + } + catch (Exception ex) + { + return (null, ex); + } + } + + public static BigInteger DifficultyToTarget(double difficulty) + { + return BigInteger.Divide(KaspaConstants.Diff1Target, new BigInteger(difficulty)); + } + + public static BigInteger CalculateTarget(uint bits) + { + (uint mant, int expt) result; + + uint unshiftedExpt = bits >> 24; + if (unshiftedExpt <= 3) + { + result.mant = (bits & 0xFFFFFF) >> (8 * (3 - (int)unshiftedExpt)); + result.expt = 0; + } + else + { + result.mant = bits & 0xFFFFFF; + result.expt = 8 * ((int)(bits >> 24) - 3); + } + + // The mantissa is signed but may not be negative + if (result.mant > 0x7FFFFF) + { + return BigInteger.Zero; + } + else + { + return BigInteger.Pow(result.mant, result.expt); + } + } + + 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); + } + + public static double BigDiffToLittle(BigInteger diff) + { + BigInteger numerator = new BigInteger(2); + numerator = numerator << 254; + + BigInteger final = BigInteger.Divide(numerator, diff); + + BigInteger tempA = BigInteger.Pow(2, 30); + final = BigInteger.Divide(final, tempA); + + return (double) final; + } + + public static BigInteger CompactToBig(uint compact) + { + uint mantissa = compact & 0x007FFFFF; + bool isNegative = (compact & 0x00800000) != 0; + uint exponent = compact >> 24; + + BigInteger result; + + if (exponent <= 3) + { + mantissa >>= (int)(8 * (3 - exponent)); + result = new BigInteger(mantissa); + } + else + { + result = new BigInteger(mantissa); + result <<= (int)(8 * (exponent - 3)); + } + + if (isNegative) + { + result = BigInteger.Negate(result); + } + + return result; + } + + public static uint BigToCompact(BigInteger n) + { + if (n.Sign == 0) + { + return 0; + } + + int exponent = n.ToByteArray().Length; + uint mantissa; + + if (exponent <= 3) + { + mantissa = (uint)n; + mantissa <<= (8 * (3 - exponent)); + } + else + { + BigInteger tmp = BigInteger.Divide(n, BigInteger.Pow(256, exponent - 3)); + mantissa = (uint)tmp; + } + + if ((mantissa & 0x00800000) != 0) + { + mantissa >>= 8; + exponent++; + } + + uint compact = (uint)(exponent << 24) | mantissa; + + if (n.Sign < 0) + { + compact |= 0x00800000; + } + + 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(); + Span hashBytes = stackalloc byte[32]; + scriptHasher.Digest(serializedScript, hashBytes); + + return hashBytes.ToArray(); + } +} + +public interface KaspaIAddress +{ + string EncodeAddress(); + byte[] ScriptAddress(); + KaspaBech32Prefix Prefix(); + byte Version(); + bool IsForPrefix(KaspaBech32Prefix prefix); +} + +public class KaspaAddressPublicKey : KaspaIAddress +{ + public byte version { get; private set; } = KaspaConstants.PubKeyAddrID; + private readonly KaspaBech32Prefix prefix; + private readonly byte[] publicKey; + + public KaspaAddressPublicKey(byte[] publicKey, KaspaBech32Prefix prefix) + { + if (publicKey.Length != KaspaConstants.PublicKeySize) + throw new ArgumentException($"Public key must be {KaspaConstants.PublicKeySize} bytes", nameof(publicKey)); + + this.prefix = prefix; + this.publicKey = publicKey.ToArray(); + } + + public string EncodeAddress() + { + return KaspaBech32.Encode(prefix.ToString(), publicKey, version); + } + + public byte[] ScriptAddress() + { + return publicKey.ToArray(); + } + + public KaspaBech32Prefix Prefix() + { + return prefix; + } + + public byte Version() + { + return version; + } + + public bool IsForPrefix(KaspaBech32Prefix prefix) + { + return this.prefix == prefix; + } + + public override string ToString() + { + return EncodeAddress(); + } +} + +public class KaspaAddressPublicKeyECDSA : KaspaIAddress +{ + public byte version { get; private set; } = KaspaConstants.PubKeyECDSAAddrID; + private readonly KaspaBech32Prefix prefix; + private readonly byte[] publicKey; + + public KaspaAddressPublicKeyECDSA(byte[] publicKey, KaspaBech32Prefix prefix) + { + if (publicKey.Length != KaspaConstants.PublicKeySizeECDSA) + throw new ArgumentException($"Public key must be {KaspaConstants.PublicKeySizeECDSA} bytes", nameof(publicKey)); + + this.prefix = prefix; + this.publicKey = publicKey.ToArray(); + } + + public string EncodeAddress() + { + return KaspaBech32.Encode(prefix.ToString(), publicKey, version); + } + + public byte[] ScriptAddress() + { + return publicKey.ToArray(); + } + + public KaspaBech32Prefix Prefix() + { + return prefix; + } + + public byte Version() + { + return version; + } + + public bool IsForPrefix(KaspaBech32Prefix prefix) + { + return this.prefix == prefix; + } + + public override string ToString() + { + return EncodeAddress(); + } +} + +public class KaspaAddressScriptHash : KaspaIAddress +{ + public byte version { get; private set; } = KaspaConstants.ScriptHashAddrID; + private readonly KaspaBech32Prefix prefix; + private readonly byte[] hash; + + public KaspaAddressScriptHash(byte[] serializedScript, KaspaBech32Prefix prefix) + { + var scriptHash = KaspaUtils.HashBlake2b(serializedScript); + if (scriptHash.Length != KaspaConstants.Blake2bSize256) + throw new ArgumentException($"Script hash must be {KaspaConstants.Blake2bSize256} bytes", nameof(scriptHash)); + + this.prefix = prefix; + this.hash = scriptHash.ToArray(); + } + + public string EncodeAddress() + { + return KaspaBech32.Encode(prefix.ToString(), hash, version); + } + + public byte[] ScriptAddress() + { + return hash.ToArray(); + } + + public KaspaBech32Prefix Prefix() + { + return prefix; + } + + public byte Version() + { + return version; + } + + public bool IsForPrefix(KaspaBech32Prefix prefix) + { + return this.prefix == prefix; + } + + public override string ToString() + { + return EncodeAddress(); + } +} + +public class KaspaAddressUtility +{ + public KaspaIAddress KaspaAddress { get; private set; } + public string CoinSymbol { get; private set; } + + public KaspaAddressUtility(string coinSymbol = "KAS") + { + this.CoinSymbol = coinSymbol; + + // Build address pattern based on network type and coin symbol + switch(this.CoinSymbol) + { + case "KLS": + this.stringsToBech32Prefixes = new Dictionary + { + { KarlsencoinConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, + { KarlsencoinConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, + { KarlsencoinConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, + { KarlsencoinConstants.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; + default: + this.stringsToBech32Prefixes = new Dictionary + { + { KaspaConstants.ChainPrefixMainnet, KaspaBech32Prefix.KaspaMain }, + { KaspaConstants.ChainPrefixDevnet, KaspaBech32Prefix.KaspaDev }, + { KaspaConstants.ChainPrefixTestnet, KaspaBech32Prefix.KaspaTest }, + { KaspaConstants.ChainPrefixSimnet, KaspaBech32Prefix.KaspaSim }, + }; + + break; + } + } + + public string EncodeAddress(KaspaBech32Prefix prefix, byte[] payload, byte version) + { + return KaspaBech32.Encode(PrefixToString(prefix), payload, version); + } + + public void DecodeAddress(string addr, KaspaBech32Prefix expectedPrefix) + { + var (prefixString, decoded, version, error) = KaspaBech32.Decode(addr); + if (error != null) + throw new ArgumentException($"Decoded address is of unknown format: {error}"); + + var prefix = ParsePrefix(prefixString); + if (expectedPrefix != KaspaBech32Prefix.Unknown && expectedPrefix != prefix) + throw new ArgumentException($"Decoded address is of wrong network. Expected {expectedPrefix.ToString()} but got {prefix.ToString()}"); + + switch (version) + { + case KaspaConstants.PubKeyAddrID: + this.KaspaAddress = new KaspaAddressPublicKey(decoded, prefix); + + break; + case KaspaConstants.PubKeyECDSAAddrID: + this.KaspaAddress = new KaspaAddressPublicKeyECDSA(decoded, prefix); + + break; + case KaspaConstants.ScriptHashAddrID: + this.KaspaAddress = new KaspaAddressScriptHash(KaspaUtils.HashBlake2b(decoded), prefix); + + break; + default: + throw new InvalidOperationException("Unknown address type"); + } + } + + public KaspaBech32Prefix ParsePrefix(string prefixString) + { + if (!stringsToBech32Prefixes.TryGetValue(prefixString, out var prefix)) + throw new ArgumentException($"Could not parse prefix {prefixString}"); + + return prefix; + } + + public string PrefixToString(KaspaBech32Prefix prefix) + { + foreach (var (key, value) in stringsToBech32Prefixes) + { + if (prefix == value) + return key; + } + + return string.Empty; + } + + private Dictionary stringsToBech32Prefixes; +} + +public static class KaspaBech32 +{ + private const string Charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + private const int ChecksumLength = 8; + + private class ConversionType + { + public byte FromBits { get; set; } + public byte ToBits { get; set; } + public bool Pad { get; set; } + } + + private static readonly ConversionType FiveToEightBits = new ConversionType { FromBits = 5, ToBits = 8, Pad = false }; + private static readonly ConversionType EightToFiveBits = new ConversionType { FromBits = 8, ToBits = 5, Pad = true }; + + private static readonly long[] Generator = { 0x98f2bc8e61, 0x79b76d99e2, 0xf33e5fb3c4, 0xae2eabe2a8, 0x1e4f43e470 }; + + public static string Encode(string prefix, byte[] payload, byte version) + { + byte[] data = new byte[payload.Length + 1]; + data[0] = version; + Array.Copy(payload, 0, data, 1, payload.Length); + + byte[] converted = ConvertBits(data, EightToFiveBits); + + return EncodeInternal(prefix, converted); + } + + public static (string, byte[], byte, Exception) Decode(string encoded) + { + try + { + var (prefix, decoded) = DecodeInternal(encoded); + var converted = ConvertBits(decoded, FiveToEightBits); + var version = converted[0]; + var payload = converted.Skip(1).ToArray(); + return (prefix, payload, version, null); + } + catch (Exception ex) + { + return (null, null, 0, ex); + } + } + + private static string EncodeInternal(string prefix, byte[] data) + { + byte[] checksum = CalculateChecksum(prefix, data); + byte[] combined = data.Concat(checksum).ToArray(); + + string base32String = EncodeToBase32(combined); + + return $"{prefix}:{base32String}"; + } + + private static (string, byte[]) DecodeInternal(string encoded) + { + if (encoded.Length < ChecksumLength + 2) + throw new Exception($"Invalid bech32 string length {encoded.Length}"); + + foreach (char c in encoded) + { + if (c < 33 || c > 126) + throw new Exception($"Invalid character in string: '{c}'"); + } + + string lower = encoded.ToLower(); + string upper = encoded.ToUpper(); + + if (encoded != lower && encoded != upper) + throw new Exception("String not all lowercase or all uppercase"); + + encoded = lower; + + int colonIndex = encoded.LastIndexOf(':'); + if (colonIndex < 1 || colonIndex + ChecksumLength + 1 > encoded.Length) + throw new Exception("Invalid index of ':'"); + + string prefix = encoded.Substring(0, colonIndex); + string data = encoded.Substring(colonIndex + 1); + + byte[] decoded = DecodeFromBase32(data); + + if (!VerifyChecksum(prefix, decoded)) + { + string checksum = encoded.Substring(encoded.Length - ChecksumLength); + string expected = EncodeToBase32(CalculateChecksum(prefix, decoded.Take(decoded.Length - ChecksumLength).ToArray())); + + throw new Exception($"Checksum failed. Expected {expected}, got {checksum}"); + } + + return (prefix, decoded.Take(decoded.Length - ChecksumLength).ToArray()); + } + + private static byte[] DecodeFromBase32(string base32String) + { + List decoded = new List(base32String.Length); + foreach (char c in base32String) + { + int index = Charset.IndexOf(c); + if (index < 0) + throw new Exception($"Invalid character not part of charset: {c}"); + + decoded.Add((byte)index); + } + return decoded.ToArray(); + } + + private static string EncodeToBase32(byte[] data) + { + StringBuilder result = new StringBuilder(data.Length); + foreach (byte b in data) + { + if (b >= Charset.Length) + return ""; + + result.Append(Charset[b]); + } + return result.ToString(); + } + + private static byte[] ConvertBits(byte[] data, ConversionType conversionType) + { + List regrouped = new List(); + byte nextByte = 0; + byte filledBits = 0; + + foreach (byte b in data) + { + byte shiftedB = (byte)(b << (8 - conversionType.FromBits)); + byte remainingFromBits = conversionType.FromBits; + + while (remainingFromBits > 0) + { + byte remainingToBits = (byte)(conversionType.ToBits - filledBits); + byte toExtract = remainingFromBits < remainingToBits ? remainingFromBits : remainingToBits; + + nextByte = (byte)((nextByte << toExtract) | (shiftedB >> (8 - toExtract))); + + shiftedB = (byte)(shiftedB << toExtract); + remainingFromBits -= toExtract; + filledBits += toExtract; + + if (filledBits == conversionType.ToBits) + { + regrouped.Add(nextByte); + filledBits = 0; + nextByte = 0; + } + } + } + + if (conversionType.Pad && filledBits > 0) + { + nextByte = (byte)(nextByte << (conversionType.ToBits - filledBits)); + regrouped.Add(nextByte); + } + + return regrouped.ToArray(); + } + + private static byte[] CalculateChecksum(string prefix, byte[] payload) + { + int[] prefixLower5Bits = PrefixToUint5Array(prefix); + int[] payloadInts = PayloadToInts(payload); + int[] templateZeroes = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + int[] concat = prefixLower5Bits.Concat(new[] { 0 }).Concat(payloadInts).Concat(templateZeroes).ToArray(); + long polyModResult = PolyMod(concat); + + byte[] res = new byte[ChecksumLength]; + for (int i = 0; i < ChecksumLength; i++) + { + res[i] = (byte)((polyModResult >> (5 * (ChecksumLength - 1 - i))) & 31); + } + + return res; + } + + private static bool VerifyChecksum(string prefix, byte[] payload) + { + int[] prefixLower5Bits = PrefixToUint5Array(prefix); + int[] payloadInts = PayloadToInts(payload); + + int[] dataToVerify = prefixLower5Bits.Concat(new[] { 0 }).Concat(payloadInts).ToArray(); + return PolyMod(dataToVerify) == 0; + } + + private static int[] PrefixToUint5Array(string prefix) + { + int[] prefixLower5Bits = new int[prefix.Length]; + for (int i = 0; i < prefix.Length; i++) + { + char c = prefix[i]; + int charLower5Bits = c & 31; + prefixLower5Bits[i] = charLower5Bits; + } + + return prefixLower5Bits; + } + + private static int[] PayloadToInts(byte[] payload) + { + return payload.Select(b => (int)b).ToArray(); + } + + private static long PolyMod(int[] values) + { + long checksum = 1; + foreach (int value in values) + { + long topBits = checksum >> 35; + checksum = ((checksum & 0x07ffffffff) << 5) ^ value; + + for (int i = 0; i < Generator.Length; i++) + { + if (((topBits >> i) & 1) == 1) + checksum ^= Generator[i]; + } + } + + return checksum ^ 1; + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs b/src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs new file mode 100644 index 000000000..4dbeee595 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/KaspaWorkerContext.cs @@ -0,0 +1,27 @@ +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Kaspa; + +public class KaspaWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// + public string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public string Worker { get; set; } + + /// + /// Unique value assigned per worker + /// + public string ExtraNonce1 { get; set; } + + /// + /// Some mining software require job to be sent in a specific way, we need to be able to identify them + /// Default: false + /// + public bool IsLargeJob { get; set; } = false; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaRPCClient.cs b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaRPCClient.cs new file mode 100644 index 000000000..6039bc5b5 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaRPCClient.cs @@ -0,0 +1 @@ +namespace Miningcore.Blockchain.Kaspa; \ 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 new file mode 100644 index 000000000..db044a7bc --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletd.cs @@ -0,0 +1,3517 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: kaspawalletd.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +namespace Miningcore.Blockchain.Kaspa.KaspaWalletd { + + using pb = global::Google.Protobuf; + using pbc = global::Google.Protobuf.Collections; + using pbr = global::Google.Protobuf.Reflection; + using scg = global::System.Collections.Generic; + + /// Holder for reflection information generated from kaspawalletd.proto + public static partial class KaspawalletdReflection { + + #region Descriptor + /// File descriptor for kaspawalletd.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static KaspawalletdReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChJrYXNwYXdhbGxldGQucHJvdG8SDEthc3BhV2FsbGV0ZCITChFHZXRCYWxh", + "bmNlUmVxdWVzdCJwChJHZXRCYWxhbmNlUmVzcG9uc2USEQoJYXZhaWxhYmxl", + "GAEgASgEEg8KB3BlbmRpbmcYAiABKAQSNgoPYWRkcmVzc0JhbGFuY2VzGAMg", + "AygLMh0uS2FzcGFXYWxsZXRkLkFkZHJlc3NCYWxhbmNlcyJGCg9BZGRyZXNz", + "QmFsYW5jZXMSDwoHYWRkcmVzcxgBIAEoCRIRCglhdmFpbGFibGUYAiABKAQS", + "DwoHcGVuZGluZxgDIAEoBCKHAQohQ3JlYXRlVW5zaWduZWRUcmFuc2FjdGlv", + "bnNSZXF1ZXN0Eg8KB2FkZHJlc3MYASABKAkSDgoGYW1vdW50GAIgASgEEgwK", + "BGZyb20YAyADKAkSIAoYdXNlRXhpc3RpbmdDaGFuZ2VBZGRyZXNzGAQgASgI", + "EhEKCWlzU2VuZEFsbBgFIAEoCCJCCiJDcmVhdGVVbnNpZ25lZFRyYW5zYWN0", + "aW9uc1Jlc3BvbnNlEhwKFHVuc2lnbmVkVHJhbnNhY3Rpb25zGAEgAygMIhYK", + "FFNob3dBZGRyZXNzZXNSZXF1ZXN0IigKFVNob3dBZGRyZXNzZXNSZXNwb25z", + "ZRIPCgdhZGRyZXNzGAEgAygJIhMKEU5ld0FkZHJlc3NSZXF1ZXN0IiUKEk5l", + "d0FkZHJlc3NSZXNwb25zZRIPCgdhZGRyZXNzGAEgASgJIjoKEEJyb2FkY2Fz", + "dFJlcXVlc3QSEAoIaXNEb21haW4YASABKAgSFAoMdHJhbnNhY3Rpb25zGAIg", + "AygMIiIKEUJyb2FkY2FzdFJlc3BvbnNlEg0KBXR4SURzGAEgAygJIhEKD1No", + "dXRkb3duUmVxdWVzdCISChBTaHV0ZG93blJlc3BvbnNlIjAKCE91dHBvaW50", + "EhUKDXRyYW5zYWN0aW9uSWQYASABKAkSDQoFaW5kZXgYAiABKA0ifgoVVXR4", + "b3NCeUFkZHJlc3Nlc0VudHJ5Eg8KB2FkZHJlc3MYASABKAkSKAoIb3V0cG9p", + "bnQYAiABKAsyFi5LYXNwYVdhbGxldGQuT3V0cG9pbnQSKgoJdXR4b0VudHJ5", + "GAMgASgLMhcuS2FzcGFXYWxsZXRkLlV0eG9FbnRyeSI7Cg9TY3JpcHRQdWJs", + "aWNLZXkSDwoHdmVyc2lvbhgBIAEoDRIXCg9zY3JpcHRQdWJsaWNLZXkYAiAB", + "KAkifgoJVXR4b0VudHJ5Eg4KBmFtb3VudBgBIAEoBBI2Cg9zY3JpcHRQdWJs", + "aWNLZXkYAiABKAsyHS5LYXNwYVdhbGxldGQuU2NyaXB0UHVibGljS2V5EhUK", + "DWJsb2NrRGFhU2NvcmUYAyABKAQSEgoKaXNDb2luYmFzZRgEIAEoCCIzCiBH", + "ZXRFeHRlcm5hbFNwZW5kYWJsZVVUWE9zUmVxdWVzdBIPCgdhZGRyZXNzGAEg", + "ASgJIlkKIUdldEV4dGVybmFsU3BlbmRhYmxlVVRYT3NSZXNwb25zZRI0CgdF", + "bnRyaWVzGAEgAygLMiMuS2FzcGFXYWxsZXRkLlV0eG9zQnlBZGRyZXNzZXNF", + "bnRyeSKFAQoLU2VuZFJlcXVlc3QSEQoJdG9BZGRyZXNzGAEgASgJEg4KBmFt", + "b3VudBgCIAEoBBIQCghwYXNzd29yZBgDIAEoCRIMCgRmcm9tGAQgAygJEiAK", + "GHVzZUV4aXN0aW5nQ2hhbmdlQWRkcmVzcxgFIAEoCBIRCglpc1NlbmRBbGwY", + "BiABKAgiOQoMU2VuZFJlc3BvbnNlEg0KBXR4SURzGAEgAygJEhoKEnNpZ25l", + "ZFRyYW5zYWN0aW9ucxgCIAMoDCI9CgtTaWduUmVxdWVzdBIcChR1bnNpZ25l", + "ZFRyYW5zYWN0aW9ucxgBIAMoDBIQCghwYXNzd29yZBgCIAEoCSIqCgxTaWdu", + "UmVzcG9uc2USGgoSc2lnbmVkVHJhbnNhY3Rpb25zGAEgAygMMrMGCgxLYXNw", + "YVdhbGxldGQSUQoKR2V0QmFsYW5jZRIfLkthc3BhV2FsbGV0ZC5HZXRCYWxh", + "bmNlUmVxdWVzdBogLkthc3BhV2FsbGV0ZC5HZXRCYWxhbmNlUmVzcG9uc2Ui", + "ABJ+ChlHZXRFeHRlcm5hbFNwZW5kYWJsZVVUWE9zEi4uS2FzcGFXYWxsZXRk", + "LkdldEV4dGVybmFsU3BlbmRhYmxlVVRYT3NSZXF1ZXN0Gi8uS2FzcGFXYWxs", + "ZXRkLkdldEV4dGVybmFsU3BlbmRhYmxlVVRYT3NSZXNwb25zZSIAEoEBChpD", + "cmVhdGVVbnNpZ25lZFRyYW5zYWN0aW9ucxIvLkthc3BhV2FsbGV0ZC5DcmVh", + "dGVVbnNpZ25lZFRyYW5zYWN0aW9uc1JlcXVlc3QaMC5LYXNwYVdhbGxldGQu", + "Q3JlYXRlVW5zaWduZWRUcmFuc2FjdGlvbnNSZXNwb25zZSIAEloKDVNob3dB", + "ZGRyZXNzZXMSIi5LYXNwYVdhbGxldGQuU2hvd0FkZHJlc3Nlc1JlcXVlc3Qa", + "Iy5LYXNwYVdhbGxldGQuU2hvd0FkZHJlc3Nlc1Jlc3BvbnNlIgASUQoKTmV3", + "QWRkcmVzcxIfLkthc3BhV2FsbGV0ZC5OZXdBZGRyZXNzUmVxdWVzdBogLkth", + "c3BhV2FsbGV0ZC5OZXdBZGRyZXNzUmVzcG9uc2UiABJLCghTaHV0ZG93bhId", + "Lkthc3BhV2FsbGV0ZC5TaHV0ZG93blJlcXVlc3QaHi5LYXNwYVdhbGxldGQu", + "U2h1dGRvd25SZXNwb25zZSIAEk4KCUJyb2FkY2FzdBIeLkthc3BhV2FsbGV0", + "ZC5Ccm9hZGNhc3RSZXF1ZXN0Gh8uS2FzcGFXYWxsZXRkLkJyb2FkY2FzdFJl", + "c3BvbnNlIgASPwoEU2VuZBIZLkthc3BhV2FsbGV0ZC5TZW5kUmVxdWVzdBoa", + "Lkthc3BhV2FsbGV0ZC5TZW5kUmVzcG9uc2UiABI/CgRTaWduEhkuS2FzcGFX", + "YWxsZXRkLlNpZ25SZXF1ZXN0GhouS2FzcGFXYWxsZXRkLlNpZ25SZXNwb25z", + "ZSIAQiuqAihNaW5pbmdjb3JlLkJsb2NrY2hhaW4uS2FzcGEuS2FzcGFXYWxs", + "ZXRkYgZwcm90bzM=")); + 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.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), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressRequest.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressResponse.Parser, new[]{ "Address" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastRequest.Parser, new[]{ "IsDomain", "Transactions" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastResponse.Parser, new[]{ "TxIDs" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownRequest), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownRequest.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownResponse), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownResponse.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.Outpoint), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.Outpoint.Parser, new[]{ "TransactionId", "Index" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxosByAddressesEntry), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxosByAddressesEntry.Parser, new[]{ "Address", "Outpoint", "UtxoEntry" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ScriptPublicKey), global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ScriptPublicKey.Parser, new[]{ "Version", "ScriptPublicKey_" }, null, null, null, null), + 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.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) + })); + } + #endregion + + } + #region Messages + public sealed partial class GetBalanceRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBalanceRequest()); + 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[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceRequest(GetBalanceRequest other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceRequest Clone() { + return new GetBalanceRequest(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBalanceRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBalanceRequest 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(GetBalanceRequest 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 GetBalanceResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBalanceResponse()); + 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[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceResponse(GetBalanceResponse other) : this() { + available_ = other.available_; + pending_ = other.pending_; + addressBalances_ = other.addressBalances_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceResponse Clone() { + return new GetBalanceResponse(this); + } + + /// Field number for the "available" field. + public const int AvailableFieldNumber = 1; + private ulong available_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Available { + get { return available_; } + set { + available_ = value; + } + } + + /// Field number for the "pending" field. + public const int PendingFieldNumber = 2; + private ulong pending_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Pending { + get { return pending_; } + set { + pending_ = value; + } + } + + /// Field number for the "addressBalances" field. + public const int AddressBalancesFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_addressBalances_codec + = pb::FieldCodec.ForMessage(26, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.AddressBalances.Parser); + private readonly pbc::RepeatedField addressBalances_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AddressBalances { + get { return addressBalances_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBalanceResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBalanceResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Available != other.Available) return false; + if (Pending != other.Pending) return false; + if(!addressBalances_.Equals(other.addressBalances_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Available != 0UL) hash ^= Available.GetHashCode(); + if (Pending != 0UL) hash ^= Pending.GetHashCode(); + hash ^= addressBalances_.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 (Available != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Available); + } + if (Pending != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(Pending); + } + addressBalances_.WriteTo(output, _repeated_addressBalances_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Available != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Available); + } + if (Pending != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Pending); + } + size += addressBalances_.CalculateSize(_repeated_addressBalances_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBalanceResponse other) { + if (other == null) { + return; + } + if (other.Available != 0UL) { + Available = other.Available; + } + if (other.Pending != 0UL) { + Pending = other.Pending; + } + addressBalances_.Add(other.addressBalances_); + _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 8: { + Available = input.ReadUInt64(); + break; + } + case 16: { + Pending = input.ReadUInt64(); + break; + } + case 26: { + addressBalances_.AddEntriesFrom(input, _repeated_addressBalances_codec); + break; + } + } + } + } + + } + + public sealed partial class AddressBalances : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AddressBalances()); + 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[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddressBalances() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddressBalances(AddressBalances other) : this() { + address_ = other.address_; + available_ = other.available_; + pending_ = other.pending_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddressBalances Clone() { + return new AddressBalances(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "available" field. + public const int AvailableFieldNumber = 2; + private ulong available_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Available { + get { return available_; } + set { + available_ = value; + } + } + + /// Field number for the "pending" field. + public const int PendingFieldNumber = 3; + private ulong pending_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Pending { + get { return pending_; } + set { + pending_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AddressBalances); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AddressBalances other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + if (Available != other.Available) return false; + if (Pending != other.Pending) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.GetHashCode(); + if (Available != 0UL) hash ^= Available.GetHashCode(); + if (Pending != 0UL) hash ^= Pending.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (Available != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(Available); + } + if (Pending != 0UL) { + output.WriteRawTag(24); + output.WriteUInt64(Pending); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (Available != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Available); + } + if (Pending != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Pending); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AddressBalances other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + if (other.Available != 0UL) { + Available = other.Available; + } + if (other.Pending != 0UL) { + Pending = other.Pending; + } + _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: { + Address = input.ReadString(); + break; + } + case 16: { + Available = input.ReadUInt64(); + break; + } + case 24: { + Pending = 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; + [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 CreateUnsignedTransactionsRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateUnsignedTransactionsRequest(CreateUnsignedTransactionsRequest other) : this() { + address_ = other.address_; + amount_ = other.amount_; + from_ = other.from_.Clone(); + useExistingChangeAddress_ = other.useExistingChangeAddress_; + isSendAll_ = other.isSendAll_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateUnsignedTransactionsRequest Clone() { + return new CreateUnsignedTransactionsRequest(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "amount" field. + public const int AmountFieldNumber = 2; + private ulong amount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Amount { + get { return amount_; } + set { + amount_ = value; + } + } + + /// Field number for the "from" field. + public const int FromFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_from_codec + = pb::FieldCodec.ForString(26); + 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 = 4; + private bool useExistingChangeAddress_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool UseExistingChangeAddress { + get { return useExistingChangeAddress_; } + set { + useExistingChangeAddress_ = value; + } + } + + /// Field number for the "isSendAll" field. + public const int IsSendAllFieldNumber = 5; + private bool isSendAll_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsSendAll { + get { return isSendAll_; } + set { + isSendAll_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateUnsignedTransactionsRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateUnsignedTransactionsRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + if (Amount != other.Amount) return false; + if(!from_.Equals(other.from_)) return false; + if (UseExistingChangeAddress != other.UseExistingChangeAddress) return false; + if (IsSendAll != other.IsSendAll) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.GetHashCode(); + if (Amount != 0UL) hash ^= Amount.GetHashCode(); + hash ^= from_.GetHashCode(); + if (UseExistingChangeAddress != false) hash ^= UseExistingChangeAddress.GetHashCode(); + if (IsSendAll != false) hash ^= IsSendAll.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (Amount != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(Amount); + } + from_.WriteTo(output, _repeated_from_codec); + if (UseExistingChangeAddress != false) { + output.WriteRawTag(32); + output.WriteBool(UseExistingChangeAddress); + } + if (IsSendAll != false) { + output.WriteRawTag(40); + output.WriteBool(IsSendAll); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (Amount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Amount); + } + size += from_.CalculateSize(_repeated_from_codec); + if (UseExistingChangeAddress != false) { + size += 1 + 1; + } + if (IsSendAll != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateUnsignedTransactionsRequest other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + if (other.Amount != 0UL) { + Amount = other.Amount; + } + from_.Add(other.from_); + if (other.UseExistingChangeAddress != false) { + UseExistingChangeAddress = other.UseExistingChangeAddress; + } + if (other.IsSendAll != false) { + IsSendAll = other.IsSendAll; + } + _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: { + Address = input.ReadString(); + break; + } + case 16: { + Amount = input.ReadUInt64(); + break; + } + case 26: { + from_.AddEntriesFrom(input, _repeated_from_codec); + break; + } + case 32: { + UseExistingChangeAddress = input.ReadBool(); + break; + } + case 40: { + IsSendAll = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class CreateUnsignedTransactionsResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new CreateUnsignedTransactionsResponse()); + 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[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateUnsignedTransactionsResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateUnsignedTransactionsResponse(CreateUnsignedTransactionsResponse other) : this() { + unsignedTransactions_ = other.unsignedTransactions_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public CreateUnsignedTransactionsResponse Clone() { + return new CreateUnsignedTransactionsResponse(this); + } + + /// Field number for the "unsignedTransactions" field. + public const int UnsignedTransactionsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_unsignedTransactions_codec + = pb::FieldCodec.ForBytes(10); + private readonly pbc::RepeatedField unsignedTransactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField UnsignedTransactions { + get { return unsignedTransactions_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as CreateUnsignedTransactionsResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(CreateUnsignedTransactionsResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!unsignedTransactions_.Equals(other.unsignedTransactions_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= unsignedTransactions_.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) { + unsignedTransactions_.WriteTo(output, _repeated_unsignedTransactions_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += unsignedTransactions_.CalculateSize(_repeated_unsignedTransactions_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(CreateUnsignedTransactionsResponse other) { + if (other == null) { + return; + } + unsignedTransactions_.Add(other.unsignedTransactions_); + _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: { + unsignedTransactions_.AddEntriesFrom(input, _repeated_unsignedTransactions_codec); + break; + } + } + } + } + + } + + public sealed partial class ShowAddressesRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShowAddressesRequest()); + 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[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShowAddressesRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShowAddressesRequest(ShowAddressesRequest other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShowAddressesRequest Clone() { + return new ShowAddressesRequest(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ShowAddressesRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ShowAddressesRequest 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(ShowAddressesRequest 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 ShowAddressesResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShowAddressesResponse()); + 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[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShowAddressesResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShowAddressesResponse(ShowAddressesResponse other) : this() { + address_ = other.address_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShowAddressesResponse Clone() { + return new ShowAddressesResponse(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_address_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField address_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Address { + get { return address_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ShowAddressesResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ShowAddressesResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!address_.Equals(other.address_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= address_.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) { + address_.WriteTo(output, _repeated_address_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += address_.CalculateSize(_repeated_address_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ShowAddressesResponse other) { + if (other == null) { + return; + } + address_.Add(other.address_); + _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: { + address_.AddEntriesFrom(input, _repeated_address_codec); + break; + } + } + } + } + + } + + public sealed partial class NewAddressRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NewAddressRequest()); + 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[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewAddressRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewAddressRequest(NewAddressRequest other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewAddressRequest Clone() { + return new NewAddressRequest(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NewAddressRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NewAddressRequest 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(NewAddressRequest 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 NewAddressResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NewAddressResponse()); + 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[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewAddressResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewAddressResponse(NewAddressResponse other) : this() { + address_ = other.address_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewAddressResponse Clone() { + return new NewAddressResponse(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NewAddressResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NewAddressResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NewAddressResponse other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + _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: { + Address = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class BroadcastRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BroadcastRequest()); + 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[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BroadcastRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BroadcastRequest(BroadcastRequest other) : this() { + isDomain_ = other.isDomain_; + transactions_ = other.transactions_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BroadcastRequest Clone() { + return new BroadcastRequest(this); + } + + /// Field number for the "isDomain" field. + public const int IsDomainFieldNumber = 1; + private bool isDomain_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsDomain { + get { return isDomain_; } + set { + isDomain_ = value; + } + } + + /// Field number for the "transactions" field. + public const int TransactionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_transactions_codec + = pb::FieldCodec.ForBytes(18); + private readonly pbc::RepeatedField transactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Transactions { + get { return transactions_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BroadcastRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BroadcastRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (IsDomain != other.IsDomain) return false; + if(!transactions_.Equals(other.transactions_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (IsDomain != false) hash ^= IsDomain.GetHashCode(); + hash ^= transactions_.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 (IsDomain != false) { + output.WriteRawTag(8); + output.WriteBool(IsDomain); + } + transactions_.WriteTo(output, _repeated_transactions_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (IsDomain != false) { + size += 1 + 1; + } + size += transactions_.CalculateSize(_repeated_transactions_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BroadcastRequest other) { + if (other == null) { + return; + } + if (other.IsDomain != false) { + IsDomain = other.IsDomain; + } + transactions_.Add(other.transactions_); + _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 8: { + IsDomain = input.ReadBool(); + break; + } + case 18: { + transactions_.AddEntriesFrom(input, _repeated_transactions_codec); + break; + } + } + } + } + + } + + public sealed partial class BroadcastResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BroadcastResponse()); + 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[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BroadcastResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BroadcastResponse(BroadcastResponse other) : this() { + txIDs_ = other.txIDs_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BroadcastResponse Clone() { + return new BroadcastResponse(this); + } + + /// Field number for the "txIDs" field. + public const int TxIDsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_txIDs_codec + = pb::FieldCodec.ForString(10); + 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 BroadcastResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BroadcastResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!txIDs_.Equals(other.txIDs_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + 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) { + txIDs_.WriteTo(output, _repeated_txIDs_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += txIDs_.CalculateSize(_repeated_txIDs_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BroadcastResponse other) { + if (other == null) { + return; + } + 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: { + txIDs_.AddEntriesFrom(input, _repeated_txIDs_codec); + break; + } + } + } + } + + } + + public sealed partial class ShutdownRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShutdownRequest()); + 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[11]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutdownRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutdownRequest(ShutdownRequest other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutdownRequest Clone() { + return new ShutdownRequest(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ShutdownRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ShutdownRequest 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(ShutdownRequest 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 ShutdownResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShutdownResponse()); + 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[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutdownResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutdownResponse(ShutdownResponse other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutdownResponse Clone() { + return new ShutdownResponse(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ShutdownResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ShutdownResponse 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(ShutdownResponse 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 Outpoint : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Outpoint()); + 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[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Outpoint() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Outpoint(Outpoint other) : this() { + transactionId_ = other.transactionId_; + index_ = other.index_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Outpoint Clone() { + return new Outpoint(this); + } + + /// Field number for the "transactionId" field. + public const int TransactionIdFieldNumber = 1; + private string transactionId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TransactionId { + get { return transactionId_; } + set { + transactionId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "index" field. + public const int IndexFieldNumber = 2; + private uint index_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Index { + get { return index_; } + set { + index_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Outpoint); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Outpoint other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (TransactionId != other.TransactionId) return false; + if (Index != other.Index) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (TransactionId.Length != 0) hash ^= TransactionId.GetHashCode(); + if (Index != 0) hash ^= Index.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 (TransactionId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(TransactionId); + } + if (Index != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Index); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (TransactionId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TransactionId); + } + if (Index != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Index); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Outpoint other) { + if (other == null) { + return; + } + if (other.TransactionId.Length != 0) { + TransactionId = other.TransactionId; + } + if (other.Index != 0) { + Index = other.Index; + } + _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: { + TransactionId = input.ReadString(); + break; + } + case 16: { + Index = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class UtxosByAddressesEntry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UtxosByAddressesEntry()); + 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[14]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosByAddressesEntry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosByAddressesEntry(UtxosByAddressesEntry other) : this() { + address_ = other.address_; + outpoint_ = other.outpoint_ != null ? other.outpoint_.Clone() : null; + utxoEntry_ = other.utxoEntry_ != null ? other.utxoEntry_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosByAddressesEntry Clone() { + return new UtxosByAddressesEntry(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "outpoint" field. + public const int OutpointFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.KaspaWalletd.Outpoint outpoint_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.KaspaWalletd.Outpoint Outpoint { + get { return outpoint_; } + set { + outpoint_ = value; + } + } + + /// Field number for the "utxoEntry" field. + public const int UtxoEntryFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxoEntry utxoEntry_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxoEntry UtxoEntry { + get { return utxoEntry_; } + set { + utxoEntry_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UtxosByAddressesEntry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UtxosByAddressesEntry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + if (!object.Equals(Outpoint, other.Outpoint)) return false; + if (!object.Equals(UtxoEntry, other.UtxoEntry)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.GetHashCode(); + if (outpoint_ != null) hash ^= Outpoint.GetHashCode(); + if (utxoEntry_ != null) hash ^= UtxoEntry.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (outpoint_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Outpoint); + } + if (utxoEntry_ != null) { + output.WriteRawTag(26); + output.WriteMessage(UtxoEntry); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (outpoint_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Outpoint); + } + if (utxoEntry_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(UtxoEntry); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UtxosByAddressesEntry other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + if (other.outpoint_ != null) { + if (outpoint_ == null) { + Outpoint = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.Outpoint(); + } + Outpoint.MergeFrom(other.Outpoint); + } + if (other.utxoEntry_ != null) { + if (utxoEntry_ == null) { + UtxoEntry = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxoEntry(); + } + UtxoEntry.MergeFrom(other.UtxoEntry); + } + _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: { + Address = input.ReadString(); + break; + } + case 18: { + if (outpoint_ == null) { + Outpoint = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.Outpoint(); + } + input.ReadMessage(Outpoint); + break; + } + case 26: { + if (utxoEntry_ == null) { + UtxoEntry = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxoEntry(); + } + input.ReadMessage(UtxoEntry); + break; + } + } + } + } + + } + + public sealed partial class ScriptPublicKey : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ScriptPublicKey()); + 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[15]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ScriptPublicKey() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ScriptPublicKey(ScriptPublicKey other) : this() { + version_ = other.version_; + scriptPublicKey_ = other.scriptPublicKey_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ScriptPublicKey Clone() { + return new ScriptPublicKey(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private uint version_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Version { + get { return version_; } + set { + version_ = value; + } + } + + /// Field number for the "scriptPublicKey" field. + public const int ScriptPublicKey_FieldNumber = 2; + private string scriptPublicKey_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ScriptPublicKey_ { + get { return scriptPublicKey_; } + set { + scriptPublicKey_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ScriptPublicKey); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ScriptPublicKey other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + if (ScriptPublicKey_ != other.ScriptPublicKey_) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version != 0) hash ^= Version.GetHashCode(); + if (ScriptPublicKey_.Length != 0) hash ^= ScriptPublicKey_.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 != 0) { + output.WriteRawTag(8); + output.WriteUInt32(Version); + } + if (ScriptPublicKey_.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ScriptPublicKey_); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Version); + } + if (ScriptPublicKey_.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ScriptPublicKey_); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ScriptPublicKey other) { + if (other == null) { + return; + } + if (other.Version != 0) { + Version = other.Version; + } + if (other.ScriptPublicKey_.Length != 0) { + ScriptPublicKey_ = other.ScriptPublicKey_; + } + _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 8: { + Version = input.ReadUInt32(); + break; + } + case 18: { + ScriptPublicKey_ = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class UtxoEntry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UtxoEntry()); + 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[16]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxoEntry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxoEntry(UtxoEntry other) : this() { + amount_ = other.amount_; + scriptPublicKey_ = other.scriptPublicKey_ != null ? other.scriptPublicKey_.Clone() : null; + blockDaaScore_ = other.blockDaaScore_; + isCoinbase_ = other.isCoinbase_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxoEntry Clone() { + return new UtxoEntry(this); + } + + /// Field number for the "amount" field. + public const int AmountFieldNumber = 1; + private ulong amount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Amount { + get { return amount_; } + set { + amount_ = value; + } + } + + /// Field number for the "scriptPublicKey" field. + public const int ScriptPublicKeyFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ScriptPublicKey scriptPublicKey_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ScriptPublicKey ScriptPublicKey { + get { return scriptPublicKey_; } + set { + scriptPublicKey_ = value; + } + } + + /// Field number for the "blockDaaScore" field. + public const int BlockDaaScoreFieldNumber = 3; + private ulong blockDaaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlockDaaScore { + get { return blockDaaScore_; } + set { + blockDaaScore_ = value; + } + } + + /// Field number for the "isCoinbase" field. + public const int IsCoinbaseFieldNumber = 4; + private bool isCoinbase_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsCoinbase { + get { return isCoinbase_; } + set { + isCoinbase_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UtxoEntry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UtxoEntry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Amount != other.Amount) return false; + if (!object.Equals(ScriptPublicKey, other.ScriptPublicKey)) return false; + if (BlockDaaScore != other.BlockDaaScore) return false; + if (IsCoinbase != other.IsCoinbase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Amount != 0UL) hash ^= Amount.GetHashCode(); + if (scriptPublicKey_ != null) hash ^= ScriptPublicKey.GetHashCode(); + if (BlockDaaScore != 0UL) hash ^= BlockDaaScore.GetHashCode(); + if (IsCoinbase != false) hash ^= IsCoinbase.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 (Amount != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Amount); + } + if (scriptPublicKey_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ScriptPublicKey); + } + if (BlockDaaScore != 0UL) { + output.WriteRawTag(24); + output.WriteUInt64(BlockDaaScore); + } + if (IsCoinbase != false) { + output.WriteRawTag(32); + output.WriteBool(IsCoinbase); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Amount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Amount); + } + if (scriptPublicKey_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ScriptPublicKey); + } + if (BlockDaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlockDaaScore); + } + if (IsCoinbase != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UtxoEntry other) { + if (other == null) { + return; + } + if (other.Amount != 0UL) { + Amount = other.Amount; + } + if (other.scriptPublicKey_ != null) { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ScriptPublicKey(); + } + ScriptPublicKey.MergeFrom(other.ScriptPublicKey); + } + if (other.BlockDaaScore != 0UL) { + BlockDaaScore = other.BlockDaaScore; + } + if (other.IsCoinbase != false) { + IsCoinbase = other.IsCoinbase; + } + _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 8: { + Amount = input.ReadUInt64(); + break; + } + case 18: { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ScriptPublicKey(); + } + input.ReadMessage(ScriptPublicKey); + break; + } + case 24: { + BlockDaaScore = input.ReadUInt64(); + break; + } + case 32: { + IsCoinbase = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class GetExternalSpendableUTXOsRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetExternalSpendableUTXOsRequest()); + 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[17]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetExternalSpendableUTXOsRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetExternalSpendableUTXOsRequest(GetExternalSpendableUTXOsRequest other) : this() { + address_ = other.address_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetExternalSpendableUTXOsRequest Clone() { + return new GetExternalSpendableUTXOsRequest(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetExternalSpendableUTXOsRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetExternalSpendableUTXOsRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetExternalSpendableUTXOsRequest other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + _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: { + Address = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class GetExternalSpendableUTXOsResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetExternalSpendableUTXOsResponse()); + 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[18]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetExternalSpendableUTXOsResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetExternalSpendableUTXOsResponse(GetExternalSpendableUTXOsResponse other) : this() { + entries_ = other.entries_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetExternalSpendableUTXOsResponse Clone() { + return new GetExternalSpendableUTXOsResponse(this); + } + + /// Field number for the "Entries" field. + public const int EntriesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_entries_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.UtxosByAddressesEntry.Parser); + private readonly pbc::RepeatedField entries_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Entries { + get { return entries_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetExternalSpendableUTXOsResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetExternalSpendableUTXOsResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!entries_.Equals(other.entries_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= entries_.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) { + entries_.WriteTo(output, _repeated_entries_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += entries_.CalculateSize(_repeated_entries_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetExternalSpendableUTXOsResponse other) { + if (other == null) { + return; + } + entries_.Add(other.entries_); + _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: { + entries_.AddEntriesFrom(input, _repeated_entries_codec); + break; + } + } + } + } + + } + + /// + /// Since SendRequest contains a password - this command should only be used on a trusted or secure connection + /// + public sealed partial class SendRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SendRequest()); + 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[19]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SendRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SendRequest(SendRequest other) : this() { + toAddress_ = other.toAddress_; + amount_ = other.amount_; + password_ = other.password_; + from_ = other.from_.Clone(); + useExistingChangeAddress_ = other.useExistingChangeAddress_; + isSendAll_ = other.isSendAll_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SendRequest Clone() { + return new SendRequest(this); + } + + /// Field number for the "toAddress" field. + public const int ToAddressFieldNumber = 1; + private string toAddress_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ToAddress { + get { return toAddress_; } + set { + toAddress_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "amount" field. + public const int AmountFieldNumber = 2; + private ulong amount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Amount { + get { return amount_; } + set { + amount_ = value; + } + } + + /// Field number for the "password" field. + public const int PasswordFieldNumber = 3; + 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 = 4; + private static readonly pb::FieldCodec _repeated_from_codec + = pb::FieldCodec.ForString(34); + 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 = 5; + private bool useExistingChangeAddress_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool UseExistingChangeAddress { + get { return useExistingChangeAddress_; } + set { + useExistingChangeAddress_ = value; + } + } + + /// Field number for the "isSendAll" field. + public const int IsSendAllFieldNumber = 6; + private bool isSendAll_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsSendAll { + get { return isSendAll_; } + set { + isSendAll_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SendRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SendRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ToAddress != other.ToAddress) return false; + if (Amount != other.Amount) return false; + if (Password != other.Password) return false; + if(!from_.Equals(other.from_)) return false; + if (UseExistingChangeAddress != other.UseExistingChangeAddress) return false; + if (IsSendAll != other.IsSendAll) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ToAddress.Length != 0) hash ^= ToAddress.GetHashCode(); + if (Amount != 0UL) hash ^= Amount.GetHashCode(); + if (Password.Length != 0) hash ^= Password.GetHashCode(); + hash ^= from_.GetHashCode(); + if (UseExistingChangeAddress != false) hash ^= UseExistingChangeAddress.GetHashCode(); + if (IsSendAll != false) hash ^= IsSendAll.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 (ToAddress.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ToAddress); + } + if (Amount != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(Amount); + } + if (Password.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Password); + } + from_.WriteTo(output, _repeated_from_codec); + if (UseExistingChangeAddress != false) { + output.WriteRawTag(40); + output.WriteBool(UseExistingChangeAddress); + } + if (IsSendAll != false) { + output.WriteRawTag(48); + output.WriteBool(IsSendAll); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ToAddress.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ToAddress); + } + if (Amount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Amount); + } + if (Password.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Password); + } + size += from_.CalculateSize(_repeated_from_codec); + if (UseExistingChangeAddress != false) { + size += 1 + 1; + } + if (IsSendAll != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SendRequest other) { + if (other == null) { + return; + } + if (other.ToAddress.Length != 0) { + ToAddress = other.ToAddress; + } + if (other.Amount != 0UL) { + Amount = other.Amount; + } + if (other.Password.Length != 0) { + Password = other.Password; + } + from_.Add(other.from_); + if (other.UseExistingChangeAddress != false) { + UseExistingChangeAddress = other.UseExistingChangeAddress; + } + if (other.IsSendAll != false) { + IsSendAll = other.IsSendAll; + } + _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: { + ToAddress = input.ReadString(); + break; + } + case 16: { + Amount = input.ReadUInt64(); + break; + } + case 26: { + Password = input.ReadString(); + break; + } + case 34: { + from_.AddEntriesFrom(input, _repeated_from_codec); + break; + } + case 40: { + UseExistingChangeAddress = input.ReadBool(); + break; + } + case 48: { + IsSendAll = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class SendResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SendResponse()); + 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[20]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SendResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SendResponse(SendResponse other) : this() { + txIDs_ = other.txIDs_.Clone(); + signedTransactions_ = other.signedTransactions_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SendResponse Clone() { + return new SendResponse(this); + } + + /// Field number for the "txIDs" field. + public const int TxIDsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_txIDs_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField txIDs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField TxIDs { + get { return txIDs_; } + } + + /// Field number for the "signedTransactions" field. + public const int SignedTransactionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_signedTransactions_codec + = pb::FieldCodec.ForBytes(18); + private readonly pbc::RepeatedField signedTransactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField SignedTransactions { + get { return signedTransactions_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SendResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SendResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!txIDs_.Equals(other.txIDs_)) return false; + if(!signedTransactions_.Equals(other.signedTransactions_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= txIDs_.GetHashCode(); + hash ^= signedTransactions_.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) { + txIDs_.WriteTo(output, _repeated_txIDs_codec); + signedTransactions_.WriteTo(output, _repeated_signedTransactions_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += txIDs_.CalculateSize(_repeated_txIDs_codec); + size += signedTransactions_.CalculateSize(_repeated_signedTransactions_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SendResponse other) { + if (other == null) { + return; + } + txIDs_.Add(other.txIDs_); + signedTransactions_.Add(other.signedTransactions_); + _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: { + txIDs_.AddEntriesFrom(input, _repeated_txIDs_codec); + break; + } + case 18: { + signedTransactions_.AddEntriesFrom(input, _repeated_signedTransactions_codec); + break; + } + } + } + } + + } + + /// + /// Since SignRequest contains a password - this command should only be used on a trusted or secure connection + /// + public sealed partial class SignRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SignRequest()); + 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[21]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SignRequest() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SignRequest(SignRequest other) : this() { + unsignedTransactions_ = other.unsignedTransactions_.Clone(); + password_ = other.password_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SignRequest Clone() { + return new SignRequest(this); + } + + /// Field number for the "unsignedTransactions" field. + public const int UnsignedTransactionsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_unsignedTransactions_codec + = pb::FieldCodec.ForBytes(10); + private readonly pbc::RepeatedField unsignedTransactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField UnsignedTransactions { + get { return unsignedTransactions_; } + } + + /// Field number for the "password" field. + public const int PasswordFieldNumber = 2; + private string password_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Password { + get { return password_; } + set { + password_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SignRequest); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SignRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!unsignedTransactions_.Equals(other.unsignedTransactions_)) return false; + if (Password != other.Password) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= unsignedTransactions_.GetHashCode(); + if (Password.Length != 0) hash ^= Password.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) { + unsignedTransactions_.WriteTo(output, _repeated_unsignedTransactions_codec); + if (Password.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Password); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += unsignedTransactions_.CalculateSize(_repeated_unsignedTransactions_codec); + if (Password.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Password); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SignRequest other) { + if (other == null) { + return; + } + unsignedTransactions_.Add(other.unsignedTransactions_); + if (other.Password.Length != 0) { + Password = other.Password; + } + _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: { + unsignedTransactions_.AddEntriesFrom(input, _repeated_unsignedTransactions_codec); + break; + } + case 18: { + Password = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class SignResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SignResponse()); + 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[22]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SignResponse() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SignResponse(SignResponse other) : this() { + signedTransactions_ = other.signedTransactions_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SignResponse Clone() { + return new SignResponse(this); + } + + /// Field number for the "signedTransactions" field. + public const int SignedTransactionsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_signedTransactions_codec + = pb::FieldCodec.ForBytes(10); + private readonly pbc::RepeatedField signedTransactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField SignedTransactions { + get { return signedTransactions_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SignResponse); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SignResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!signedTransactions_.Equals(other.signedTransactions_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= signedTransactions_.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) { + signedTransactions_.WriteTo(output, _repeated_signedTransactions_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += signedTransactions_.CalculateSize(_repeated_signedTransactions_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SignResponse other) { + if (other == null) { + return; + } + signedTransactions_.Add(other.signedTransactions_); + _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: { + signedTransactions_.AddEntriesFrom(input, _repeated_signedTransactions_codec); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs new file mode 100644 index 000000000..a477c24b8 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/KaspaWalletdGrpc.cs @@ -0,0 +1,461 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: RPC/KaspaWalletd/kaspawalletd.proto +// +// Original file comments: +// https://raw.githubusercontent.com/kaspanet/kaspad/master/cmd/kaspawallet/daemon/pb/kaspawalletd.proto +#pragma warning disable 0414, 1591, 8981, 0612 +#region Designer generated code + +namespace Miningcore.Blockchain.Kaspa.KaspaWalletd { + + using grpc = global::Grpc.Core; + + public partial class KaspaWalletdRPC + { + public KaspaWalletdRPC(string __ServiceName) + { + this.__Method_GetBalance = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetBalance", + __Marshaller_KaspaWalletdRPC_GetBalanceRequest, + __Marshaller_KaspaWalletdRPC_GetBalanceResponse); + + this.__Method_GetExternalSpendableUTXOs = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "GetExternalSpendableUTXOs", + __Marshaller_KaspaWalletdRPC_GetExternalSpendableUTXOsRequest, + __Marshaller_KaspaWalletdRPC_GetExternalSpendableUTXOsResponse); + + this.__Method_CreateUnsignedTransactions = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "CreateUnsignedTransactions", + __Marshaller_KaspaWalletdRPC_CreateUnsignedTransactionsRequest, + __Marshaller_KaspaWalletdRPC_CreateUnsignedTransactionsResponse); + + this.__Method_ShowAddresses = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "ShowAddresses", + __Marshaller_KaspaWalletdRPC_ShowAddressesRequest, + __Marshaller_KaspaWalletdRPC_ShowAddressesResponse); + + this.__Method_NewAddress = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "NewAddress", + __Marshaller_KaspaWalletdRPC_NewAddressRequest, + __Marshaller_KaspaWalletdRPC_NewAddressResponse); + + this.__Method_Shutdown = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Shutdown", + __Marshaller_KaspaWalletdRPC_ShutdownRequest, + __Marshaller_KaspaWalletdRPC_ShutdownResponse); + + this.__Method_Broadcast = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Broadcast", + __Marshaller_KaspaWalletdRPC_BroadcastRequest, + __Marshaller_KaspaWalletdRPC_BroadcastResponse); + + this.__Method_Send = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Send", + __Marshaller_KaspaWalletdRPC_SendRequest, + __Marshaller_KaspaWalletdRPC_SendResponse); + + this.__Method_Sign = new grpc::Method( + grpc::MethodType.Unary, + __ServiceName, + "Sign", + __Marshaller_KaspaWalletdRPC_SignRequest, + __Marshaller_KaspaWalletdRPC_SignResponse); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context) + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (message is global::Google.Protobuf.IBufferMessage) + { + context.SetPayloadLength(message.CalculateSize()); + global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter()); + context.Complete(); + return; + } + #endif + context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static class __Helper_MessageCache + { + public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static T __Helper_DeserializeMessage(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser parser) where T : global::Google.Protobuf.IMessage + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (__Helper_MessageCache.IsBufferMessage) + { + return parser.ParseFrom(context.PayloadAsReadOnlySequence()); + } + #endif + return parser.ParseFrom(context.PayloadAsNewBuffer()); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_GetBalanceRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_GetBalanceResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_GetExternalSpendableUTXOsRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_GetExternalSpendableUTXOsResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_CreateUnsignedTransactionsRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_CreateUnsignedTransactionsResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_ShowAddressesRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_ShowAddressesResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_NewAddressRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_NewAddressResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_ShutdownRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_ShutdownResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_BroadcastRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_BroadcastResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_SendRequest = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_KaspaWalletdRPC_SendResponse = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendResponse.Parser)); + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + 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)] + public grpc::Method __Method_GetBalance { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_GetExternalSpendableUTXOs { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_CreateUnsignedTransactions { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_ShowAddresses { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_NewAddress { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_Shutdown { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_Broadcast { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_Send { get; private set; } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_Sign { get; private set; } + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Miningcore.Blockchain.Kaspa.KaspaWalletd.KaspawalletdReflection.Descriptor.Services[0]; } + } + + /// Client for KaspaWalletdRPC + public partial class KaspaWalletdRPCClient : grpc::ClientBase + { + public KaspaWalletdRPC __KaspaWalletdRPC { get; private set; } + + /// Creates a new client for KaspaWalletdRPC + /// The channel to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public KaspaWalletdRPCClient(KaspaWalletdRPC __KaspaWalletdRPC, grpc::ChannelBase channel) : base(channel) + { + this.__KaspaWalletdRPC = __KaspaWalletdRPC; + } + /// Creates a new client for KaspaWalletdRPC that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public KaspaWalletdRPCClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected KaspaWalletdRPCClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected KaspaWalletdRPCClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceResponse GetBalance(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetBalance(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceResponse GetBalance(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_GetBalance, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall GetBalanceAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetBalanceAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall GetBalanceAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetBalanceRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_GetBalance, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsResponse GetExternalSpendableUTXOs(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetExternalSpendableUTXOs(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsResponse GetExternalSpendableUTXOs(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_GetExternalSpendableUTXOs, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall GetExternalSpendableUTXOsAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return GetExternalSpendableUTXOsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall GetExternalSpendableUTXOsAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.GetExternalSpendableUTXOsRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_GetExternalSpendableUTXOs, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsResponse CreateUnsignedTransactions(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CreateUnsignedTransactions(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsResponse CreateUnsignedTransactions(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_CreateUnsignedTransactions, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CreateUnsignedTransactionsAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return CreateUnsignedTransactionsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall CreateUnsignedTransactionsAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.CreateUnsignedTransactionsRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_CreateUnsignedTransactions, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesResponse ShowAddresses(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ShowAddresses(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesResponse ShowAddresses(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_ShowAddresses, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ShowAddressesAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ShowAddressesAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ShowAddressesAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShowAddressesRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_ShowAddresses, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressResponse NewAddress(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return NewAddress(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressResponse NewAddress(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_NewAddress, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall NewAddressAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return NewAddressAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall NewAddressAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.NewAddressRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_NewAddress, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownResponse Shutdown(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Shutdown(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownResponse Shutdown(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_Shutdown, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ShutdownAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return ShutdownAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall ShutdownAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.ShutdownRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_Shutdown, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastResponse Broadcast(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Broadcast(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastResponse Broadcast(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_Broadcast, null, options, request); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall BroadcastAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return BroadcastAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall BroadcastAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.BroadcastRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_Broadcast, null, options, request); + } + /// + /// Since SendRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The initial metadata to send with the call. This parameter is optional. + /// An optional deadline for the call. The call will be cancelled if deadline is hit. + /// An optional token for canceling the call. + /// The response received from the server. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendResponse Send(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Send(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + /// + /// Since SendRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The options for the call. + /// The response received from the server. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendResponse Send(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_Send, null, options, request); + } + /// + /// Since SendRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The initial metadata to send with the call. This parameter is optional. + /// An optional deadline for the call. The call will be cancelled if deadline is hit. + /// An optional token for canceling the call. + /// The call object. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall SendAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return SendAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + /// + /// Since SendRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The options for the call. + /// The call object. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall SendAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SendRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_Send, null, options, request); + } + /// + /// Since SignRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The initial metadata to send with the call. This parameter is optional. + /// An optional deadline for the call. The call will be cancelled if deadline is hit. + /// An optional token for canceling the call. + /// The response received from the server. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignResponse Sign(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return Sign(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + /// + /// Since SignRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The options for the call. + /// The response received from the server. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignResponse Sign(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignRequest request, grpc::CallOptions options) + { + return CallInvoker.BlockingUnaryCall(__KaspaWalletdRPC.__Method_Sign, null, options, request); + } + /// + /// Since SignRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The initial metadata to send with the call. This parameter is optional. + /// An optional deadline for the call. The call will be cancelled if deadline is hit. + /// An optional token for canceling the call. + /// The call object. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall SignAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return SignAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); + } + /// + /// Since SignRequest contains a password - this command should only be used on a trusted or secure connection + /// + /// The request to send to the server. + /// The options for the call. + /// The call object. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncUnaryCall SignAsync(global::Miningcore.Blockchain.Kaspa.KaspaWalletd.SignRequest request, grpc::CallOptions options) + { + return CallInvoker.AsyncUnaryCall(__KaspaWalletdRPC.__Method_Sign, 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) + { + return new KaspaWalletdRPCClient(configuration); + } + } + + } +} +#endregion diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto new file mode 100644 index 000000000..ca665aa6a --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/KaspaWalletd/kaspawalletd.proto @@ -0,0 +1,129 @@ +syntax = "proto3"; + +option go_package = "github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"; +package kaspawalletd; + +service kaspawalletd { + rpc GetBalance (GetBalanceRequest) returns (GetBalanceResponse) {} + rpc GetExternalSpendableUTXOs (GetExternalSpendableUTXOsRequest) returns (GetExternalSpendableUTXOsResponse) {} + rpc CreateUnsignedTransactions (CreateUnsignedTransactionsRequest) returns (CreateUnsignedTransactionsResponse) {} + rpc ShowAddresses (ShowAddressesRequest) returns (ShowAddressesResponse) {} + rpc NewAddress (NewAddressRequest) returns (NewAddressResponse) {} + rpc Shutdown (ShutdownRequest) returns (ShutdownResponse) {} + rpc Broadcast (BroadcastRequest) returns (BroadcastResponse) {} + // Since SendRequest contains a password - this command should only be used on a trusted or secure connection + 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) {} +} + +message GetBalanceRequest { +} + +message GetBalanceResponse { + uint64 available = 1; + uint64 pending = 2; + repeated AddressBalances addressBalances = 3; +} + +message AddressBalances { + string address = 1; + uint64 available = 2; + uint64 pending = 3; +} + +message CreateUnsignedTransactionsRequest { + string address = 1; + uint64 amount = 2; + repeated string from = 3; + bool useExistingChangeAddress = 4; + bool isSendAll = 5; +} + +message CreateUnsignedTransactionsResponse { + repeated bytes unsignedTransactions = 1; +} + +message ShowAddressesRequest { +} + +message ShowAddressesResponse { + repeated string address = 1; +} + +message NewAddressRequest { +} + +message NewAddressResponse { + string address = 1; +} + +message BroadcastRequest { + bool isDomain = 1; + repeated bytes transactions = 2; +} + +message BroadcastResponse { + repeated string txIDs = 1; +} + +message ShutdownRequest { +} + +message ShutdownResponse { +} + +message Outpoint { + string transactionId = 1; + uint32 index = 2; +} + +message UtxosByAddressesEntry { + string address = 1; + Outpoint outpoint = 2; + UtxoEntry utxoEntry = 3; +} + +message ScriptPublicKey { + uint32 version = 1; + string scriptPublicKey = 2; +} + +message UtxoEntry { + uint64 amount = 1; + ScriptPublicKey scriptPublicKey = 2; + uint64 blockDaaScore = 3; + bool isCoinbase = 4; +} + +message GetExternalSpendableUTXOsRequest{ + string address = 1; +} + +message GetExternalSpendableUTXOsResponse{ + repeated UtxosByAddressesEntry Entries = 1; +} +// Since SendRequest contains a password - this command should only be used on a trusted or secure connection +message SendRequest{ + string toAddress = 1; + uint64 amount = 2; + string password = 3; + repeated string from = 4; + bool useExistingChangeAddress = 5; + bool isSendAll = 6; +} + +message SendResponse{ + repeated string txIDs = 1; + repeated bytes signedTransactions = 2; +} + +// Since SignRequest contains a password - this command should only be used on a trusted or secure connection +message SignRequest{ + repeated bytes unsignedTransactions = 1; + string password = 2; +} + +message SignResponse{ + repeated bytes signedTransactions = 1; +} diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Messages.cs b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Messages.cs new file mode 100644 index 000000000..0d3ccfe6e --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Messages.cs @@ -0,0 +1,5479 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: messages.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +namespace Miningcore.Blockchain.Kaspa.Kaspad { + + using pb = global::Google.Protobuf; + using pbc = global::Google.Protobuf.Collections; + using pbr = global::Google.Protobuf.Reflection; + using scg = global::System.Collections.Generic; + + /// Holder for reflection information generated from messages.proto + public static partial class MessagesReflection { + + #region Descriptor + /// File descriptor for messages.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static MessagesReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Cg5tZXNzYWdlcy5wcm90bxIJcHJvdG93aXJlGglwMnAucHJvdG8aCXJwYy5w", + "cm90byLRUgoNS2FzcGFkTWVzc2FnZRIwCglhZGRyZXNzZXMYASABKAsyGy5w", + "cm90b3dpcmUuQWRkcmVzc2VzTWVzc2FnZUgAEigKBWJsb2NrGAIgASgLMhcu", + "cHJvdG93aXJlLkJsb2NrTWVzc2FnZUgAEjQKC3RyYW5zYWN0aW9uGAMgASgL", + "Mh0ucHJvdG93aXJlLlRyYW5zYWN0aW9uTWVzc2FnZUgAEjYKDGJsb2NrTG9j", + "YXRvchgFIAEoCzIeLnByb3Rvd2lyZS5CbG9ja0xvY2F0b3JNZXNzYWdlSAAS", + "PgoQcmVxdWVzdEFkZHJlc3NlcxgGIAEoCzIiLnByb3Rvd2lyZS5SZXF1ZXN0", + "QWRkcmVzc2VzTWVzc2FnZUgAEkIKEnJlcXVlc3RSZWxheUJsb2NrcxgKIAEo", + "CzIkLnByb3Rvd2lyZS5SZXF1ZXN0UmVsYXlCbG9ja3NNZXNzYWdlSAASRAoT", + "cmVxdWVzdFRyYW5zYWN0aW9ucxgMIAEoCzIlLnByb3Rvd2lyZS5SZXF1ZXN0", + "VHJhbnNhY3Rpb25zTWVzc2FnZUgAEisKCGliZEJsb2NrGA0gASgLMhcucHJv", + "dG93aXJlLkJsb2NrTWVzc2FnZUgAEjgKDWludlJlbGF5QmxvY2sYDiABKAsy", + "Hy5wcm90b3dpcmUuSW52UmVsYXlCbG9ja01lc3NhZ2VIABI8Cg9pbnZUcmFu", + "c2FjdGlvbnMYDyABKAsyIS5wcm90b3dpcmUuSW52VHJhbnNhY3Rpb25zTWVz", + "c2FnZUgAEiYKBHBpbmcYECABKAsyFi5wcm90b3dpcmUuUGluZ01lc3NhZ2VI", + "ABImCgRwb25nGBEgASgLMhYucHJvdG93aXJlLlBvbmdNZXNzYWdlSAASKgoG", + "dmVyYWNrGBMgASgLMhgucHJvdG93aXJlLlZlcmFja01lc3NhZ2VIABIsCgd2", + "ZXJzaW9uGBQgASgLMhkucHJvdG93aXJlLlZlcnNpb25NZXNzYWdlSAASRAoT", + "dHJhbnNhY3Rpb25Ob3RGb3VuZBgVIAEoCzIlLnByb3Rvd2lyZS5UcmFuc2Fj", + "dGlvbk5vdEZvdW5kTWVzc2FnZUgAEioKBnJlamVjdBgWIAEoCzIYLnByb3Rv", + "d2lyZS5SZWplY3RNZXNzYWdlSAASTgoYcHJ1bmluZ1BvaW50VXR4b1NldENo", + "dW5rGBkgASgLMioucHJvdG93aXJlLlBydW5pbmdQb2ludFV0eG9TZXRDaHVu", + "a01lc3NhZ2VIABI+ChByZXF1ZXN0SUJEQmxvY2tzGBogASgLMiIucHJvdG93", + "aXJlLlJlcXVlc3RJQkRCbG9ja3NNZXNzYWdlSAASSgoWdW5leHBlY3RlZFBy", + "dW5pbmdQb2ludBgbIAEoCzIoLnByb3Rvd2lyZS5VbmV4cGVjdGVkUHJ1bmlu", + "Z1BvaW50TWVzc2FnZUgAEjwKD2liZEJsb2NrTG9jYXRvchgeIAEoCzIhLnBy", + "b3Rvd2lyZS5JYmRCbG9ja0xvY2F0b3JNZXNzYWdlSAASUgoaaWJkQmxvY2tM", + "b2NhdG9ySGlnaGVzdEhhc2gYHyABKAsyLC5wcm90b3dpcmUuSWJkQmxvY2tM", + "b2NhdG9ySGlnaGVzdEhhc2hNZXNzYWdlSAASZAojcmVxdWVzdE5leHRQcnVu", + "aW5nUG9pbnRVdHhvU2V0Q2h1bmsYISABKAsyNS5wcm90b3dpcmUuUmVxdWVz", + "dE5leHRQcnVuaW5nUG9pbnRVdHhvU2V0Q2h1bmtNZXNzYWdlSAASWAodZG9u", + "ZVBydW5pbmdQb2ludFV0eG9TZXRDaHVua3MYIiABKAsyLy5wcm90b3dpcmUu", + "RG9uZVBydW5pbmdQb2ludFV0eG9TZXRDaHVua3NNZXNzYWdlSAASYgoiaWJk", + "QmxvY2tMb2NhdG9ySGlnaGVzdEhhc2hOb3RGb3VuZBgjIAEoCzI0LnByb3Rv", + "d2lyZS5JYmRCbG9ja0xvY2F0b3JIaWdoZXN0SGFzaE5vdEZvdW5kTWVzc2Fn", + "ZUgAEkYKFGJsb2NrV2l0aFRydXN0ZWREYXRhGCQgASgLMiYucHJvdG93aXJl", + "LkJsb2NrV2l0aFRydXN0ZWREYXRhTWVzc2FnZUgAElAKGWRvbmVCbG9ja3NX", + "aXRoVHJ1c3RlZERhdGEYJSABKAsyKy5wcm90b3dpcmUuRG9uZUJsb2Nrc1dp", + "dGhUcnVzdGVkRGF0YU1lc3NhZ2VIABJgCiFyZXF1ZXN0UHJ1bmluZ1BvaW50", + "QW5kSXRzQW50aWNvbmUYKCABKAsyMy5wcm90b3dpcmUuUmVxdWVzdFBydW5p", + "bmdQb2ludEFuZEl0c0FudGljb25lTWVzc2FnZUgAEjYKDGJsb2NrSGVhZGVy", + "cxgpIAEoCzIeLnByb3Rvd2lyZS5CbG9ja0hlYWRlcnNNZXNzYWdlSAASQgoS", + "cmVxdWVzdE5leHRIZWFkZXJzGCogASgLMiQucHJvdG93aXJlLlJlcXVlc3RO", + "ZXh0SGVhZGVyc01lc3NhZ2VIABI0CgtEb25lSGVhZGVycxgrIAEoCzIdLnBy", + "b3Rvd2lyZS5Eb25lSGVhZGVyc01lc3NhZ2VIABJSChpyZXF1ZXN0UHJ1bmlu", + "Z1BvaW50VVRYT1NldBgsIAEoCzIsLnByb3Rvd2lyZS5SZXF1ZXN0UHJ1bmlu", + "Z1BvaW50VVRYT1NldE1lc3NhZ2VIABI6Cg5yZXF1ZXN0SGVhZGVycxgtIAEo", + "CzIgLnByb3Rvd2lyZS5SZXF1ZXN0SGVhZGVyc01lc3NhZ2VIABJEChNyZXF1", + "ZXN0QmxvY2tMb2NhdG9yGC4gASgLMiUucHJvdG93aXJlLlJlcXVlc3RCbG9j", + "a0xvY2F0b3JNZXNzYWdlSAASOAoNcHJ1bmluZ1BvaW50cxgvIAEoCzIfLnBy", + "b3Rvd2lyZS5QcnVuaW5nUG9pbnRzTWVzc2FnZUgAEk4KGHJlcXVlc3RQcnVu", + "aW5nUG9pbnRQcm9vZhgwIAEoCzIqLnByb3Rvd2lyZS5SZXF1ZXN0UHJ1bmlu", + "Z1BvaW50UHJvb2ZNZXNzYWdlSAASQAoRcHJ1bmluZ1BvaW50UHJvb2YYMSAB", + "KAsyIy5wcm90b3dpcmUuUHJ1bmluZ1BvaW50UHJvb2ZNZXNzYWdlSAASKAoF", + "cmVhZHkYMiABKAsyFy5wcm90b3dpcmUuUmVhZHlNZXNzYWdlSAASSgoWYmxv", + "Y2tXaXRoVHJ1c3RlZERhdGFWNBgzIAEoCzIoLnByb3Rvd2lyZS5CbG9ja1dp", + "dGhUcnVzdGVkRGF0YVY0TWVzc2FnZUgAEjQKC3RydXN0ZWREYXRhGDQgASgL", + "Mh0ucHJvdG93aXJlLlRydXN0ZWREYXRhTWVzc2FnZUgAElQKG3JlcXVlc3RJ", + "QkRDaGFpbkJsb2NrTG9jYXRvchg1IAEoCzItLnByb3Rvd2lyZS5SZXF1ZXN0", + "SUJEQ2hhaW5CbG9ja0xvY2F0b3JNZXNzYWdlSAASRgoUaWJkQ2hhaW5CbG9j", + "a0xvY2F0b3IYNiABKAsyJi5wcm90b3dpcmUuSWJkQ2hhaW5CbG9ja0xvY2F0", + "b3JNZXNzYWdlSAASPAoPcmVxdWVzdEFudGljb25lGDcgASgLMiEucHJvdG93", + "aXJlLlJlcXVlc3RBbnRpY29uZU1lc3NhZ2VIABJ0CityZXF1ZXN0TmV4dFBy", + "dW5pbmdQb2ludEFuZEl0c0FudGljb25lQmxvY2tzGDggASgLMj0ucHJvdG93", + "aXJlLlJlcXVlc3ROZXh0UHJ1bmluZ1BvaW50QW5kSXRzQW50aWNvbmVCbG9j", + "a3NNZXNzYWdlSAASTwoYZ2V0Q3VycmVudE5ldHdvcmtSZXF1ZXN0GOkHIAEo", + "CzIqLnByb3Rvd2lyZS5HZXRDdXJyZW50TmV0d29ya1JlcXVlc3RNZXNzYWdl", + "SAASUQoZZ2V0Q3VycmVudE5ldHdvcmtSZXNwb25zZRjqByABKAsyKy5wcm90", + "b3dpcmUuR2V0Q3VycmVudE5ldHdvcmtSZXNwb25zZU1lc3NhZ2VIABJDChJz", + "dWJtaXRCbG9ja1JlcXVlc3QY6wcgASgLMiQucHJvdG93aXJlLlN1Ym1pdEJs", + "b2NrUmVxdWVzdE1lc3NhZ2VIABJFChNzdWJtaXRCbG9ja1Jlc3BvbnNlGOwH", + "IAEoCzIlLnByb3Rvd2lyZS5TdWJtaXRCbG9ja1Jlc3BvbnNlTWVzc2FnZUgA", + "Ek0KF2dldEJsb2NrVGVtcGxhdGVSZXF1ZXN0GO0HIAEoCzIpLnByb3Rvd2ly", + "ZS5HZXRCbG9ja1RlbXBsYXRlUmVxdWVzdE1lc3NhZ2VIABJPChhnZXRCbG9j", + "a1RlbXBsYXRlUmVzcG9uc2UY7gcgASgLMioucHJvdG93aXJlLkdldEJsb2Nr", + "VGVtcGxhdGVSZXNwb25zZU1lc3NhZ2VIABJNChdub3RpZnlCbG9ja0FkZGVk", + "UmVxdWVzdBjvByABKAsyKS5wcm90b3dpcmUuTm90aWZ5QmxvY2tBZGRlZFJl", + "cXVlc3RNZXNzYWdlSAASTwoYbm90aWZ5QmxvY2tBZGRlZFJlc3BvbnNlGPAH", + "IAEoCzIqLnByb3Rvd2lyZS5Ob3RpZnlCbG9ja0FkZGVkUmVzcG9uc2VNZXNz", + "YWdlSAASSwoWYmxvY2tBZGRlZE5vdGlmaWNhdGlvbhjxByABKAsyKC5wcm90", + "b3dpcmUuQmxvY2tBZGRlZE5vdGlmaWNhdGlvbk1lc3NhZ2VIABJNChdnZXRQ", + "ZWVyQWRkcmVzc2VzUmVxdWVzdBjyByABKAsyKS5wcm90b3dpcmUuR2V0UGVl", + "ckFkZHJlc3Nlc1JlcXVlc3RNZXNzYWdlSAASTwoYZ2V0UGVlckFkZHJlc3Nl", + "c1Jlc3BvbnNlGPMHIAEoCzIqLnByb3Rvd2lyZS5HZXRQZWVyQWRkcmVzc2Vz", + "UmVzcG9uc2VNZXNzYWdlSAASUQoZZ2V0U2VsZWN0ZWRUaXBIYXNoUmVxdWVz", + "dBj0ByABKAsyKy5wcm90b3dpcmUuR2V0U2VsZWN0ZWRUaXBIYXNoUmVxdWVz", + "dE1lc3NhZ2VIABJTChpnZXRTZWxlY3RlZFRpcEhhc2hSZXNwb25zZRj1ByAB", + "KAsyLC5wcm90b3dpcmUuR2V0U2VsZWN0ZWRUaXBIYXNoUmVzcG9uc2VNZXNz", + "YWdlSAASSwoWZ2V0TWVtcG9vbEVudHJ5UmVxdWVzdBj2ByABKAsyKC5wcm90", + "b3dpcmUuR2V0TWVtcG9vbEVudHJ5UmVxdWVzdE1lc3NhZ2VIABJNChdnZXRN", + "ZW1wb29sRW50cnlSZXNwb25zZRj3ByABKAsyKS5wcm90b3dpcmUuR2V0TWVt", + "cG9vbEVudHJ5UmVzcG9uc2VNZXNzYWdlSAASVQobZ2V0Q29ubmVjdGVkUGVl", + "ckluZm9SZXF1ZXN0GPgHIAEoCzItLnByb3Rvd2lyZS5HZXRDb25uZWN0ZWRQ", + "ZWVySW5mb1JlcXVlc3RNZXNzYWdlSAASVwocZ2V0Q29ubmVjdGVkUGVlcklu", + "Zm9SZXNwb25zZRj5ByABKAsyLi5wcm90b3dpcmUuR2V0Q29ubmVjdGVkUGVl", + "ckluZm9SZXNwb25zZU1lc3NhZ2VIABI7Cg5hZGRQZWVyUmVxdWVzdBj6ByAB", + "KAsyIC5wcm90b3dpcmUuQWRkUGVlclJlcXVlc3RNZXNzYWdlSAASPQoPYWRk", + "UGVlclJlc3BvbnNlGPsHIAEoCzIhLnByb3Rvd2lyZS5BZGRQZWVyUmVzcG9u", + "c2VNZXNzYWdlSAASTwoYc3VibWl0VHJhbnNhY3Rpb25SZXF1ZXN0GPwHIAEo", + "CzIqLnByb3Rvd2lyZS5TdWJtaXRUcmFuc2FjdGlvblJlcXVlc3RNZXNzYWdl", + "SAASUQoZc3VibWl0VHJhbnNhY3Rpb25SZXNwb25zZRj9ByABKAsyKy5wcm90", + "b3dpcmUuU3VibWl0VHJhbnNhY3Rpb25SZXNwb25zZU1lc3NhZ2VIABJ7Ci5u", + "b3RpZnlWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRDaGFpbkNoYW5nZWRSZXF1ZXN0", + "GP4HIAEoCzJALnByb3Rvd2lyZS5Ob3RpZnlWaXJ0dWFsU2VsZWN0ZWRQYXJl", + "bnRDaGFpbkNoYW5nZWRSZXF1ZXN0TWVzc2FnZUgAEn0KL25vdGlmeVZpcnR1", + "YWxTZWxlY3RlZFBhcmVudENoYWluQ2hhbmdlZFJlc3BvbnNlGP8HIAEoCzJB", + "LnByb3Rvd2lyZS5Ob3RpZnlWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRDaGFpbkNo", + "YW5nZWRSZXNwb25zZU1lc3NhZ2VIABJ5Ci12aXJ0dWFsU2VsZWN0ZWRQYXJl", + "bnRDaGFpbkNoYW5nZWROb3RpZmljYXRpb24YgAggASgLMj8ucHJvdG93aXJl", + "LlZpcnR1YWxTZWxlY3RlZFBhcmVudENoYWluQ2hhbmdlZE5vdGlmaWNhdGlv", + "bk1lc3NhZ2VIABI9Cg9nZXRCbG9ja1JlcXVlc3QYgQggASgLMiEucHJvdG93", + "aXJlLkdldEJsb2NrUmVxdWVzdE1lc3NhZ2VIABI/ChBnZXRCbG9ja1Jlc3Bv", + "bnNlGIIIIAEoCzIiLnByb3Rvd2lyZS5HZXRCbG9ja1Jlc3BvbnNlTWVzc2Fn", + "ZUgAEkcKFGdldFN1Ym5ldHdvcmtSZXF1ZXN0GIMIIAEoCzImLnByb3Rvd2ly", + "ZS5HZXRTdWJuZXR3b3JrUmVxdWVzdE1lc3NhZ2VIABJJChVnZXRTdWJuZXR3", + "b3JrUmVzcG9uc2UYhAggASgLMicucHJvdG93aXJlLkdldFN1Ym5ldHdvcmtS", + "ZXNwb25zZU1lc3NhZ2VIABJ5Ci1nZXRWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRD", + "aGFpbkZyb21CbG9ja1JlcXVlc3QYhQggASgLMj8ucHJvdG93aXJlLkdldFZp", + "cnR1YWxTZWxlY3RlZFBhcmVudENoYWluRnJvbUJsb2NrUmVxdWVzdE1lc3Nh", + "Z2VIABJ7Ci5nZXRWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRDaGFpbkZyb21CbG9j", + "a1Jlc3BvbnNlGIYIIAEoCzJALnByb3Rvd2lyZS5HZXRWaXJ0dWFsU2VsZWN0", + "ZWRQYXJlbnRDaGFpbkZyb21CbG9ja1Jlc3BvbnNlTWVzc2FnZUgAEj8KEGdl", + "dEJsb2Nrc1JlcXVlc3QYhwggASgLMiIucHJvdG93aXJlLkdldEJsb2Nrc1Jl", + "cXVlc3RNZXNzYWdlSAASQQoRZ2V0QmxvY2tzUmVzcG9uc2UYiAggASgLMiMu", + "cHJvdG93aXJlLkdldEJsb2Nrc1Jlc3BvbnNlTWVzc2FnZUgAEkcKFGdldEJs", + "b2NrQ291bnRSZXF1ZXN0GIkIIAEoCzImLnByb3Rvd2lyZS5HZXRCbG9ja0Nv", + "dW50UmVxdWVzdE1lc3NhZ2VIABJJChVnZXRCbG9ja0NvdW50UmVzcG9uc2UY", + "igggASgLMicucHJvdG93aXJlLkdldEJsb2NrQ291bnRSZXNwb25zZU1lc3Nh", + "Z2VIABJLChZnZXRCbG9ja0RhZ0luZm9SZXF1ZXN0GIsIIAEoCzIoLnByb3Rv", + "d2lyZS5HZXRCbG9ja0RhZ0luZm9SZXF1ZXN0TWVzc2FnZUgAEk0KF2dldEJs", + "b2NrRGFnSW5mb1Jlc3BvbnNlGIwIIAEoCzIpLnByb3Rvd2lyZS5HZXRCbG9j", + "a0RhZ0luZm9SZXNwb25zZU1lc3NhZ2VIABJbCh5yZXNvbHZlRmluYWxpdHlD", + "b25mbGljdFJlcXVlc3QYjQggASgLMjAucHJvdG93aXJlLlJlc29sdmVGaW5h", + "bGl0eUNvbmZsaWN0UmVxdWVzdE1lc3NhZ2VIABJdCh9yZXNvbHZlRmluYWxp", + "dHlDb25mbGljdFJlc3BvbnNlGI4IIAEoCzIxLnByb3Rvd2lyZS5SZXNvbHZl", + "RmluYWxpdHlDb25mbGljdFJlc3BvbnNlTWVzc2FnZUgAElsKHm5vdGlmeUZp", + "bmFsaXR5Q29uZmxpY3RzUmVxdWVzdBiPCCABKAsyMC5wcm90b3dpcmUuTm90", + "aWZ5RmluYWxpdHlDb25mbGljdHNSZXF1ZXN0TWVzc2FnZUgAEl0KH25vdGlm", + "eUZpbmFsaXR5Q29uZmxpY3RzUmVzcG9uc2UYkAggASgLMjEucHJvdG93aXJl", + "Lk5vdGlmeUZpbmFsaXR5Q29uZmxpY3RzUmVzcG9uc2VNZXNzYWdlSAASVwoc", + "ZmluYWxpdHlDb25mbGljdE5vdGlmaWNhdGlvbhiRCCABKAsyLi5wcm90b3dp", + "cmUuRmluYWxpdHlDb25mbGljdE5vdGlmaWNhdGlvbk1lc3NhZ2VIABJnCiRm", + "aW5hbGl0eUNvbmZsaWN0UmVzb2x2ZWROb3RpZmljYXRpb24YkgggASgLMjYu", + "cHJvdG93aXJlLkZpbmFsaXR5Q29uZmxpY3RSZXNvbHZlZE5vdGlmaWNhdGlv", + "bk1lc3NhZ2VIABJPChhnZXRNZW1wb29sRW50cmllc1JlcXVlc3QYkwggASgL", + "MioucHJvdG93aXJlLkdldE1lbXBvb2xFbnRyaWVzUmVxdWVzdE1lc3NhZ2VI", + "ABJRChlnZXRNZW1wb29sRW50cmllc1Jlc3BvbnNlGJQIIAEoCzIrLnByb3Rv", + "d2lyZS5HZXRNZW1wb29sRW50cmllc1Jlc3BvbnNlTWVzc2FnZUgAEj0KD3No", + "dXREb3duUmVxdWVzdBiVCCABKAsyIS5wcm90b3dpcmUuU2h1dERvd25SZXF1", + "ZXN0TWVzc2FnZUgAEj8KEHNodXREb3duUmVzcG9uc2UYlgggASgLMiIucHJv", + "dG93aXJlLlNodXREb3duUmVzcG9uc2VNZXNzYWdlSAASQQoRZ2V0SGVhZGVy", + "c1JlcXVlc3QYlwggASgLMiMucHJvdG93aXJlLkdldEhlYWRlcnNSZXF1ZXN0", + "TWVzc2FnZUgAEkMKEmdldEhlYWRlcnNSZXNwb25zZRiYCCABKAsyJC5wcm90", + "b3dpcmUuR2V0SGVhZGVyc1Jlc3BvbnNlTWVzc2FnZUgAElEKGW5vdGlmeVV0", + "eG9zQ2hhbmdlZFJlcXVlc3QYmQggASgLMisucHJvdG93aXJlLk5vdGlmeVV0", + "eG9zQ2hhbmdlZFJlcXVlc3RNZXNzYWdlSAASUwoabm90aWZ5VXR4b3NDaGFu", + "Z2VkUmVzcG9uc2UYmgggASgLMiwucHJvdG93aXJlLk5vdGlmeVV0eG9zQ2hh", + "bmdlZFJlc3BvbnNlTWVzc2FnZUgAEk8KGHV0eG9zQ2hhbmdlZE5vdGlmaWNh", + "dGlvbhibCCABKAsyKi5wcm90b3dpcmUuVXR4b3NDaGFuZ2VkTm90aWZpY2F0", + "aW9uTWVzc2FnZUgAElMKGmdldFV0eG9zQnlBZGRyZXNzZXNSZXF1ZXN0GJwI", + "IAEoCzIsLnByb3Rvd2lyZS5HZXRVdHhvc0J5QWRkcmVzc2VzUmVxdWVzdE1l", + "c3NhZ2VIABJVChtnZXRVdHhvc0J5QWRkcmVzc2VzUmVzcG9uc2UYnQggASgL", + "Mi0ucHJvdG93aXJlLkdldFV0eG9zQnlBZGRyZXNzZXNSZXNwb25zZU1lc3Nh", + "Z2VIABJvCihnZXRWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRCbHVlU2NvcmVSZXF1", + "ZXN0GJ4IIAEoCzI6LnByb3Rvd2lyZS5HZXRWaXJ0dWFsU2VsZWN0ZWRQYXJl", + "bnRCbHVlU2NvcmVSZXF1ZXN0TWVzc2FnZUgAEnEKKWdldFZpcnR1YWxTZWxl", + "Y3RlZFBhcmVudEJsdWVTY29yZVJlc3BvbnNlGJ8IIAEoCzI7LnByb3Rvd2ly", + "ZS5HZXRWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRCbHVlU2NvcmVSZXNwb25zZU1l", + "c3NhZ2VIABKDAQoybm90aWZ5VmlydHVhbFNlbGVjdGVkUGFyZW50Qmx1ZVNj", + "b3JlQ2hhbmdlZFJlcXVlc3QYoAggASgLMkQucHJvdG93aXJlLk5vdGlmeVZp", + "cnR1YWxTZWxlY3RlZFBhcmVudEJsdWVTY29yZUNoYW5nZWRSZXF1ZXN0TWVz", + "c2FnZUgAEoUBCjNub3RpZnlWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRCbHVlU2Nv", + "cmVDaGFuZ2VkUmVzcG9uc2UYoQggASgLMkUucHJvdG93aXJlLk5vdGlmeVZp", + "cnR1YWxTZWxlY3RlZFBhcmVudEJsdWVTY29yZUNoYW5nZWRSZXNwb25zZU1l", + "c3NhZ2VIABKBAQoxdmlydHVhbFNlbGVjdGVkUGFyZW50Qmx1ZVNjb3JlQ2hh", + "bmdlZE5vdGlmaWNhdGlvbhiiCCABKAsyQy5wcm90b3dpcmUuVmlydHVhbFNl", + "bGVjdGVkUGFyZW50Qmx1ZVNjb3JlQ2hhbmdlZE5vdGlmaWNhdGlvbk1lc3Nh", + "Z2VIABIzCgpiYW5SZXF1ZXN0GKMIIAEoCzIcLnByb3Rvd2lyZS5CYW5SZXF1", + "ZXN0TWVzc2FnZUgAEjUKC2JhblJlc3BvbnNlGKQIIAEoCzIdLnByb3Rvd2ly", + "ZS5CYW5SZXNwb25zZU1lc3NhZ2VIABI3Cgx1bmJhblJlcXVlc3QYpQggASgL", + "Mh4ucHJvdG93aXJlLlVuYmFuUmVxdWVzdE1lc3NhZ2VIABI5Cg11bmJhblJl", + "c3BvbnNlGKYIIAEoCzIfLnByb3Rvd2lyZS5VbmJhblJlc3BvbnNlTWVzc2Fn", + "ZUgAEjsKDmdldEluZm9SZXF1ZXN0GKcIIAEoCzIgLnByb3Rvd2lyZS5HZXRJ", + "bmZvUmVxdWVzdE1lc3NhZ2VIABI9Cg9nZXRJbmZvUmVzcG9uc2UYqAggASgL", + "MiEucHJvdG93aXJlLkdldEluZm9SZXNwb25zZU1lc3NhZ2VIABJfCiBzdG9w", + "Tm90aWZ5aW5nVXR4b3NDaGFuZ2VkUmVxdWVzdBipCCABKAsyMi5wcm90b3dp", + "cmUuU3RvcE5vdGlmeWluZ1V0eG9zQ2hhbmdlZFJlcXVlc3RNZXNzYWdlSAAS", + "YQohc3RvcE5vdGlmeWluZ1V0eG9zQ2hhbmdlZFJlc3BvbnNlGKoIIAEoCzIz", + "LnByb3Rvd2lyZS5TdG9wTm90aWZ5aW5nVXR4b3NDaGFuZ2VkUmVzcG9uc2VN", + "ZXNzYWdlSAASbwoobm90aWZ5UHJ1bmluZ1BvaW50VVRYT1NldE92ZXJyaWRl", + "UmVxdWVzdBirCCABKAsyOi5wcm90b3dpcmUuTm90aWZ5UHJ1bmluZ1BvaW50", + "VVRYT1NldE92ZXJyaWRlUmVxdWVzdE1lc3NhZ2VIABJxCilub3RpZnlQcnVu", + "aW5nUG9pbnRVVFhPU2V0T3ZlcnJpZGVSZXNwb25zZRisCCABKAsyOy5wcm90", + "b3dpcmUuTm90aWZ5UHJ1bmluZ1BvaW50VVRYT1NldE92ZXJyaWRlUmVzcG9u", + "c2VNZXNzYWdlSAASbQoncHJ1bmluZ1BvaW50VVRYT1NldE92ZXJyaWRlTm90", + "aWZpY2F0aW9uGK0IIAEoCzI5LnByb3Rvd2lyZS5QcnVuaW5nUG9pbnRVVFhP", + "U2V0T3ZlcnJpZGVOb3RpZmljYXRpb25NZXNzYWdlSAASfQovc3RvcE5vdGlm", + "eWluZ1BydW5pbmdQb2ludFVUWE9TZXRPdmVycmlkZVJlcXVlc3QYrgggASgL", + "MkEucHJvdG93aXJlLlN0b3BOb3RpZnlpbmdQcnVuaW5nUG9pbnRVVFhPU2V0", + "T3ZlcnJpZGVSZXF1ZXN0TWVzc2FnZUgAEn8KMHN0b3BOb3RpZnlpbmdQcnVu", + "aW5nUG9pbnRVVFhPU2V0T3ZlcnJpZGVSZXNwb25zZRivCCABKAsyQi5wcm90", + "b3dpcmUuU3RvcE5vdGlmeWluZ1BydW5pbmdQb2ludFVUWE9TZXRPdmVycmlk", + "ZVJlc3BvbnNlTWVzc2FnZUgAEmkKJWVzdGltYXRlTmV0d29ya0hhc2hlc1Bl", + "clNlY29uZFJlcXVlc3QYsAggASgLMjcucHJvdG93aXJlLkVzdGltYXRlTmV0", + "d29ya0hhc2hlc1BlclNlY29uZFJlcXVlc3RNZXNzYWdlSAASawomZXN0aW1h", + "dGVOZXR3b3JrSGFzaGVzUGVyU2Vjb25kUmVzcG9uc2UYsQggASgLMjgucHJv", + "dG93aXJlLkVzdGltYXRlTmV0d29ya0hhc2hlc1BlclNlY29uZFJlc3BvbnNl", + "TWVzc2FnZUgAEmUKI25vdGlmeVZpcnR1YWxEYWFTY29yZUNoYW5nZWRSZXF1", + "ZXN0GLIIIAEoCzI1LnByb3Rvd2lyZS5Ob3RpZnlWaXJ0dWFsRGFhU2NvcmVD", + "aGFuZ2VkUmVxdWVzdE1lc3NhZ2VIABJnCiRub3RpZnlWaXJ0dWFsRGFhU2Nv", + "cmVDaGFuZ2VkUmVzcG9uc2UYswggASgLMjYucHJvdG93aXJlLk5vdGlmeVZp", + "cnR1YWxEYWFTY29yZUNoYW5nZWRSZXNwb25zZU1lc3NhZ2VIABJjCiJ2aXJ0", + "dWFsRGFhU2NvcmVDaGFuZ2VkTm90aWZpY2F0aW9uGLQIIAEoCzI0LnByb3Rv", + "d2lyZS5WaXJ0dWFsRGFhU2NvcmVDaGFuZ2VkTm90aWZpY2F0aW9uTWVzc2Fn", + "ZUgAElMKGmdldEJhbGFuY2VCeUFkZHJlc3NSZXF1ZXN0GLUIIAEoCzIsLnBy", + "b3Rvd2lyZS5HZXRCYWxhbmNlQnlBZGRyZXNzUmVxdWVzdE1lc3NhZ2VIABJV", + "ChtnZXRCYWxhbmNlQnlBZGRyZXNzUmVzcG9uc2UYtgggASgLMi0ucHJvdG93", + "aXJlLkdldEJhbGFuY2VCeUFkZHJlc3NSZXNwb25zZU1lc3NhZ2VIABJZCh1n", + "ZXRCYWxhbmNlc0J5QWRkcmVzc2VzUmVxdWVzdBi3CCABKAsyLy5wcm90b3dp", + "cmUuR2V0QmFsYW5jZXNCeUFkZHJlc3Nlc1JlcXVlc3RNZXNzYWdlSAASWwoe", + "Z2V0QmFsYW5jZXNCeUFkZHJlc3Nlc1Jlc3BvbnNlGLgIIAEoCzIwLnByb3Rv", + "d2lyZS5HZXRCYWxhbmNlc0J5QWRkcmVzc2VzUmVzcG9uc2VNZXNzYWdlSAAS", + "WQodbm90aWZ5TmV3QmxvY2tUZW1wbGF0ZVJlcXVlc3QYuQggASgLMi8ucHJv", + "dG93aXJlLk5vdGlmeU5ld0Jsb2NrVGVtcGxhdGVSZXF1ZXN0TWVzc2FnZUgA", + "ElsKHm5vdGlmeU5ld0Jsb2NrVGVtcGxhdGVSZXNwb25zZRi6CCABKAsyMC5w", + "cm90b3dpcmUuTm90aWZ5TmV3QmxvY2tUZW1wbGF0ZVJlc3BvbnNlTWVzc2Fn", + "ZUgAElcKHG5ld0Jsb2NrVGVtcGxhdGVOb3RpZmljYXRpb24YuwggASgLMi4u", + "cHJvdG93aXJlLk5ld0Jsb2NrVGVtcGxhdGVOb3RpZmljYXRpb25NZXNzYWdl", + "SAASZQojZ2V0TWVtcG9vbEVudHJpZXNCeUFkZHJlc3Nlc1JlcXVlc3QYvAgg", + "ASgLMjUucHJvdG93aXJlLkdldE1lbXBvb2xFbnRyaWVzQnlBZGRyZXNzZXNS", + "ZXF1ZXN0TWVzc2FnZUgAEmcKJGdldE1lbXBvb2xFbnRyaWVzQnlBZGRyZXNz", + "ZXNSZXNwb25zZRi9CCABKAsyNi5wcm90b3dpcmUuR2V0TWVtcG9vbEVudHJp", + "ZXNCeUFkZHJlc3Nlc1Jlc3BvbnNlTWVzc2FnZUgAEkcKFGdldENvaW5TdXBw", + "bHlSZXF1ZXN0GL4IIAEoCzImLnByb3Rvd2lyZS5HZXRDb2luU3VwcGx5UmVx", + "dWVzdE1lc3NhZ2VIABJJChVnZXRDb2luU3VwcGx5UmVzcG9uc2UYvwggASgL", + "MicucHJvdG93aXJlLkdldENvaW5TdXBwbHlSZXNwb25zZU1lc3NhZ2VIAEIJ", + "CgdwYXlsb2FkMlAKA1AyUBJJCg1NZXNzYWdlU3RyZWFtEhgucHJvdG93aXJl", + "Lkthc3BhZE1lc3NhZ2UaGC5wcm90b3dpcmUuS2FzcGFkTWVzc2FnZSIAKAEw", + "ATJQCgNSUEMSSQoNTWVzc2FnZVN0cmVhbRIYLnByb3Rvd2lyZS5LYXNwYWRN", + "ZXNzYWdlGhgucHJvdG93aXJlLkthc3BhZE1lc3NhZ2UiACgBMAFCJaoCIk1p", + "bmluZ2NvcmUuQmxvY2tjaGFpbi5LYXNwYS5LYXNwYWRiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::Miningcore.Blockchain.Kaspa.Kaspad.P2PReflection.Descriptor, global::Miningcore.Blockchain.Kaspa.Kaspad.RpcReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.KaspadMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.KaspadMessage.Parser, new[]{ "Addresses", "Block", "Transaction", "BlockLocator", "RequestAddresses", "RequestRelayBlocks", "RequestTransactions", "IbdBlock", "InvRelayBlock", "InvTransactions", "Ping", "Pong", "Verack", "Version", "TransactionNotFound", "Reject", "PruningPointUtxoSetChunk", "RequestIBDBlocks", "UnexpectedPruningPoint", "IbdBlockLocator", "IbdBlockLocatorHighestHash", "RequestNextPruningPointUtxoSetChunk", "DonePruningPointUtxoSetChunks", "IbdBlockLocatorHighestHashNotFound", "BlockWithTrustedData", "DoneBlocksWithTrustedData", "RequestPruningPointAndItsAnticone", "BlockHeaders", "RequestNextHeaders", "DoneHeaders", "RequestPruningPointUTXOSet", "RequestHeaders", "RequestBlockLocator", "PruningPoints", "RequestPruningPointProof", "PruningPointProof", "Ready", "BlockWithTrustedDataV4", "TrustedData", "RequestIBDChainBlockLocator", "IbdChainBlockLocator", "RequestAnticone", "RequestNextPruningPointAndItsAnticoneBlocks", "GetCurrentNetworkRequest", "GetCurrentNetworkResponse", "SubmitBlockRequest", "SubmitBlockResponse", "GetBlockTemplateRequest", "GetBlockTemplateResponse", "NotifyBlockAddedRequest", "NotifyBlockAddedResponse", "BlockAddedNotification", "GetPeerAddressesRequest", "GetPeerAddressesResponse", "GetSelectedTipHashRequest", "GetSelectedTipHashResponse", "GetMempoolEntryRequest", "GetMempoolEntryResponse", "GetConnectedPeerInfoRequest", "GetConnectedPeerInfoResponse", "AddPeerRequest", "AddPeerResponse", "SubmitTransactionRequest", "SubmitTransactionResponse", "NotifyVirtualSelectedParentChainChangedRequest", "NotifyVirtualSelectedParentChainChangedResponse", "VirtualSelectedParentChainChangedNotification", "GetBlockRequest", "GetBlockResponse", "GetSubnetworkRequest", "GetSubnetworkResponse", "GetVirtualSelectedParentChainFromBlockRequest", "GetVirtualSelectedParentChainFromBlockResponse", "GetBlocksRequest", "GetBlocksResponse", "GetBlockCountRequest", "GetBlockCountResponse", "GetBlockDagInfoRequest", "GetBlockDagInfoResponse", "ResolveFinalityConflictRequest", "ResolveFinalityConflictResponse", "NotifyFinalityConflictsRequest", "NotifyFinalityConflictsResponse", "FinalityConflictNotification", "FinalityConflictResolvedNotification", "GetMempoolEntriesRequest", "GetMempoolEntriesResponse", "ShutDownRequest", "ShutDownResponse", "GetHeadersRequest", "GetHeadersResponse", "NotifyUtxosChangedRequest", "NotifyUtxosChangedResponse", "UtxosChangedNotification", "GetUtxosByAddressesRequest", "GetUtxosByAddressesResponse", "GetVirtualSelectedParentBlueScoreRequest", "GetVirtualSelectedParentBlueScoreResponse", "NotifyVirtualSelectedParentBlueScoreChangedRequest", "NotifyVirtualSelectedParentBlueScoreChangedResponse", "VirtualSelectedParentBlueScoreChangedNotification", "BanRequest", "BanResponse", "UnbanRequest", "UnbanResponse", "GetInfoRequest", "GetInfoResponse", "StopNotifyingUtxosChangedRequest", "StopNotifyingUtxosChangedResponse", "NotifyPruningPointUTXOSetOverrideRequest", "NotifyPruningPointUTXOSetOverrideResponse", "PruningPointUTXOSetOverrideNotification", "StopNotifyingPruningPointUTXOSetOverrideRequest", "StopNotifyingPruningPointUTXOSetOverrideResponse", "EstimateNetworkHashesPerSecondRequest", "EstimateNetworkHashesPerSecondResponse", "NotifyVirtualDaaScoreChangedRequest", "NotifyVirtualDaaScoreChangedResponse", "VirtualDaaScoreChangedNotification", "GetBalanceByAddressRequest", "GetBalanceByAddressResponse", "GetBalancesByAddressesRequest", "GetBalancesByAddressesResponse", "NotifyNewBlockTemplateRequest", "NotifyNewBlockTemplateResponse", "NewBlockTemplateNotification", "GetMempoolEntriesByAddressesRequest", "GetMempoolEntriesByAddressesResponse", "GetCoinSupplyRequest", "GetCoinSupplyResponse" }, new[]{ "Payload" }, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class KaspadMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new KaspadMessage()); + 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.Kaspad.MessagesReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KaspadMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KaspadMessage(KaspadMessage other) : this() { + switch (other.PayloadCase) { + case PayloadOneofCase.Addresses: + Addresses = other.Addresses.Clone(); + break; + case PayloadOneofCase.Block: + Block = other.Block.Clone(); + break; + case PayloadOneofCase.Transaction: + Transaction = other.Transaction.Clone(); + break; + case PayloadOneofCase.BlockLocator: + BlockLocator = other.BlockLocator.Clone(); + break; + case PayloadOneofCase.RequestAddresses: + RequestAddresses = other.RequestAddresses.Clone(); + break; + case PayloadOneofCase.RequestRelayBlocks: + RequestRelayBlocks = other.RequestRelayBlocks.Clone(); + break; + case PayloadOneofCase.RequestTransactions: + RequestTransactions = other.RequestTransactions.Clone(); + break; + case PayloadOneofCase.IbdBlock: + IbdBlock = other.IbdBlock.Clone(); + break; + case PayloadOneofCase.InvRelayBlock: + InvRelayBlock = other.InvRelayBlock.Clone(); + break; + case PayloadOneofCase.InvTransactions: + InvTransactions = other.InvTransactions.Clone(); + break; + case PayloadOneofCase.Ping: + Ping = other.Ping.Clone(); + break; + case PayloadOneofCase.Pong: + Pong = other.Pong.Clone(); + break; + case PayloadOneofCase.Verack: + Verack = other.Verack.Clone(); + break; + case PayloadOneofCase.Version: + Version = other.Version.Clone(); + break; + case PayloadOneofCase.TransactionNotFound: + TransactionNotFound = other.TransactionNotFound.Clone(); + break; + case PayloadOneofCase.Reject: + Reject = other.Reject.Clone(); + break; + case PayloadOneofCase.PruningPointUtxoSetChunk: + PruningPointUtxoSetChunk = other.PruningPointUtxoSetChunk.Clone(); + break; + case PayloadOneofCase.RequestIBDBlocks: + RequestIBDBlocks = other.RequestIBDBlocks.Clone(); + break; + case PayloadOneofCase.UnexpectedPruningPoint: + UnexpectedPruningPoint = other.UnexpectedPruningPoint.Clone(); + break; + case PayloadOneofCase.IbdBlockLocator: + IbdBlockLocator = other.IbdBlockLocator.Clone(); + break; + case PayloadOneofCase.IbdBlockLocatorHighestHash: + IbdBlockLocatorHighestHash = other.IbdBlockLocatorHighestHash.Clone(); + break; + case PayloadOneofCase.RequestNextPruningPointUtxoSetChunk: + RequestNextPruningPointUtxoSetChunk = other.RequestNextPruningPointUtxoSetChunk.Clone(); + break; + case PayloadOneofCase.DonePruningPointUtxoSetChunks: + DonePruningPointUtxoSetChunks = other.DonePruningPointUtxoSetChunks.Clone(); + break; + case PayloadOneofCase.IbdBlockLocatorHighestHashNotFound: + IbdBlockLocatorHighestHashNotFound = other.IbdBlockLocatorHighestHashNotFound.Clone(); + break; + case PayloadOneofCase.BlockWithTrustedData: + BlockWithTrustedData = other.BlockWithTrustedData.Clone(); + break; + case PayloadOneofCase.DoneBlocksWithTrustedData: + DoneBlocksWithTrustedData = other.DoneBlocksWithTrustedData.Clone(); + break; + case PayloadOneofCase.RequestPruningPointAndItsAnticone: + RequestPruningPointAndItsAnticone = other.RequestPruningPointAndItsAnticone.Clone(); + break; + case PayloadOneofCase.BlockHeaders: + BlockHeaders = other.BlockHeaders.Clone(); + break; + case PayloadOneofCase.RequestNextHeaders: + RequestNextHeaders = other.RequestNextHeaders.Clone(); + break; + case PayloadOneofCase.DoneHeaders: + DoneHeaders = other.DoneHeaders.Clone(); + break; + case PayloadOneofCase.RequestPruningPointUTXOSet: + RequestPruningPointUTXOSet = other.RequestPruningPointUTXOSet.Clone(); + break; + case PayloadOneofCase.RequestHeaders: + RequestHeaders = other.RequestHeaders.Clone(); + break; + case PayloadOneofCase.RequestBlockLocator: + RequestBlockLocator = other.RequestBlockLocator.Clone(); + break; + case PayloadOneofCase.PruningPoints: + PruningPoints = other.PruningPoints.Clone(); + break; + case PayloadOneofCase.RequestPruningPointProof: + RequestPruningPointProof = other.RequestPruningPointProof.Clone(); + break; + case PayloadOneofCase.PruningPointProof: + PruningPointProof = other.PruningPointProof.Clone(); + break; + case PayloadOneofCase.Ready: + Ready = other.Ready.Clone(); + break; + case PayloadOneofCase.BlockWithTrustedDataV4: + BlockWithTrustedDataV4 = other.BlockWithTrustedDataV4.Clone(); + break; + case PayloadOneofCase.TrustedData: + TrustedData = other.TrustedData.Clone(); + break; + case PayloadOneofCase.RequestIBDChainBlockLocator: + RequestIBDChainBlockLocator = other.RequestIBDChainBlockLocator.Clone(); + break; + case PayloadOneofCase.IbdChainBlockLocator: + IbdChainBlockLocator = other.IbdChainBlockLocator.Clone(); + break; + case PayloadOneofCase.RequestAnticone: + RequestAnticone = other.RequestAnticone.Clone(); + break; + case PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks: + RequestNextPruningPointAndItsAnticoneBlocks = other.RequestNextPruningPointAndItsAnticoneBlocks.Clone(); + break; + case PayloadOneofCase.GetCurrentNetworkRequest: + GetCurrentNetworkRequest = other.GetCurrentNetworkRequest.Clone(); + break; + case PayloadOneofCase.GetCurrentNetworkResponse: + GetCurrentNetworkResponse = other.GetCurrentNetworkResponse.Clone(); + break; + case PayloadOneofCase.SubmitBlockRequest: + SubmitBlockRequest = other.SubmitBlockRequest.Clone(); + break; + case PayloadOneofCase.SubmitBlockResponse: + SubmitBlockResponse = other.SubmitBlockResponse.Clone(); + break; + case PayloadOneofCase.GetBlockTemplateRequest: + GetBlockTemplateRequest = other.GetBlockTemplateRequest.Clone(); + break; + case PayloadOneofCase.GetBlockTemplateResponse: + GetBlockTemplateResponse = other.GetBlockTemplateResponse.Clone(); + break; + case PayloadOneofCase.NotifyBlockAddedRequest: + NotifyBlockAddedRequest = other.NotifyBlockAddedRequest.Clone(); + break; + case PayloadOneofCase.NotifyBlockAddedResponse: + NotifyBlockAddedResponse = other.NotifyBlockAddedResponse.Clone(); + break; + case PayloadOneofCase.BlockAddedNotification: + BlockAddedNotification = other.BlockAddedNotification.Clone(); + break; + case PayloadOneofCase.GetPeerAddressesRequest: + GetPeerAddressesRequest = other.GetPeerAddressesRequest.Clone(); + break; + case PayloadOneofCase.GetPeerAddressesResponse: + GetPeerAddressesResponse = other.GetPeerAddressesResponse.Clone(); + break; + case PayloadOneofCase.GetSelectedTipHashRequest: + GetSelectedTipHashRequest = other.GetSelectedTipHashRequest.Clone(); + break; + case PayloadOneofCase.GetSelectedTipHashResponse: + GetSelectedTipHashResponse = other.GetSelectedTipHashResponse.Clone(); + break; + case PayloadOneofCase.GetMempoolEntryRequest: + GetMempoolEntryRequest = other.GetMempoolEntryRequest.Clone(); + break; + case PayloadOneofCase.GetMempoolEntryResponse: + GetMempoolEntryResponse = other.GetMempoolEntryResponse.Clone(); + break; + case PayloadOneofCase.GetConnectedPeerInfoRequest: + GetConnectedPeerInfoRequest = other.GetConnectedPeerInfoRequest.Clone(); + break; + case PayloadOneofCase.GetConnectedPeerInfoResponse: + GetConnectedPeerInfoResponse = other.GetConnectedPeerInfoResponse.Clone(); + break; + case PayloadOneofCase.AddPeerRequest: + AddPeerRequest = other.AddPeerRequest.Clone(); + break; + case PayloadOneofCase.AddPeerResponse: + AddPeerResponse = other.AddPeerResponse.Clone(); + break; + case PayloadOneofCase.SubmitTransactionRequest: + SubmitTransactionRequest = other.SubmitTransactionRequest.Clone(); + break; + case PayloadOneofCase.SubmitTransactionResponse: + SubmitTransactionResponse = other.SubmitTransactionResponse.Clone(); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest: + NotifyVirtualSelectedParentChainChangedRequest = other.NotifyVirtualSelectedParentChainChangedRequest.Clone(); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse: + NotifyVirtualSelectedParentChainChangedResponse = other.NotifyVirtualSelectedParentChainChangedResponse.Clone(); + break; + case PayloadOneofCase.VirtualSelectedParentChainChangedNotification: + VirtualSelectedParentChainChangedNotification = other.VirtualSelectedParentChainChangedNotification.Clone(); + break; + case PayloadOneofCase.GetBlockRequest: + GetBlockRequest = other.GetBlockRequest.Clone(); + break; + case PayloadOneofCase.GetBlockResponse: + GetBlockResponse = other.GetBlockResponse.Clone(); + break; + case PayloadOneofCase.GetSubnetworkRequest: + GetSubnetworkRequest = other.GetSubnetworkRequest.Clone(); + break; + case PayloadOneofCase.GetSubnetworkResponse: + GetSubnetworkResponse = other.GetSubnetworkResponse.Clone(); + break; + case PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest: + GetVirtualSelectedParentChainFromBlockRequest = other.GetVirtualSelectedParentChainFromBlockRequest.Clone(); + break; + case PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse: + GetVirtualSelectedParentChainFromBlockResponse = other.GetVirtualSelectedParentChainFromBlockResponse.Clone(); + break; + case PayloadOneofCase.GetBlocksRequest: + GetBlocksRequest = other.GetBlocksRequest.Clone(); + break; + case PayloadOneofCase.GetBlocksResponse: + GetBlocksResponse = other.GetBlocksResponse.Clone(); + break; + case PayloadOneofCase.GetBlockCountRequest: + GetBlockCountRequest = other.GetBlockCountRequest.Clone(); + break; + case PayloadOneofCase.GetBlockCountResponse: + GetBlockCountResponse = other.GetBlockCountResponse.Clone(); + break; + case PayloadOneofCase.GetBlockDagInfoRequest: + GetBlockDagInfoRequest = other.GetBlockDagInfoRequest.Clone(); + break; + case PayloadOneofCase.GetBlockDagInfoResponse: + GetBlockDagInfoResponse = other.GetBlockDagInfoResponse.Clone(); + break; + case PayloadOneofCase.ResolveFinalityConflictRequest: + ResolveFinalityConflictRequest = other.ResolveFinalityConflictRequest.Clone(); + break; + case PayloadOneofCase.ResolveFinalityConflictResponse: + ResolveFinalityConflictResponse = other.ResolveFinalityConflictResponse.Clone(); + break; + case PayloadOneofCase.NotifyFinalityConflictsRequest: + NotifyFinalityConflictsRequest = other.NotifyFinalityConflictsRequest.Clone(); + break; + case PayloadOneofCase.NotifyFinalityConflictsResponse: + NotifyFinalityConflictsResponse = other.NotifyFinalityConflictsResponse.Clone(); + break; + case PayloadOneofCase.FinalityConflictNotification: + FinalityConflictNotification = other.FinalityConflictNotification.Clone(); + break; + case PayloadOneofCase.FinalityConflictResolvedNotification: + FinalityConflictResolvedNotification = other.FinalityConflictResolvedNotification.Clone(); + break; + case PayloadOneofCase.GetMempoolEntriesRequest: + GetMempoolEntriesRequest = other.GetMempoolEntriesRequest.Clone(); + break; + case PayloadOneofCase.GetMempoolEntriesResponse: + GetMempoolEntriesResponse = other.GetMempoolEntriesResponse.Clone(); + break; + case PayloadOneofCase.ShutDownRequest: + ShutDownRequest = other.ShutDownRequest.Clone(); + break; + case PayloadOneofCase.ShutDownResponse: + ShutDownResponse = other.ShutDownResponse.Clone(); + break; + case PayloadOneofCase.GetHeadersRequest: + GetHeadersRequest = other.GetHeadersRequest.Clone(); + break; + case PayloadOneofCase.GetHeadersResponse: + GetHeadersResponse = other.GetHeadersResponse.Clone(); + break; + case PayloadOneofCase.NotifyUtxosChangedRequest: + NotifyUtxosChangedRequest = other.NotifyUtxosChangedRequest.Clone(); + break; + case PayloadOneofCase.NotifyUtxosChangedResponse: + NotifyUtxosChangedResponse = other.NotifyUtxosChangedResponse.Clone(); + break; + case PayloadOneofCase.UtxosChangedNotification: + UtxosChangedNotification = other.UtxosChangedNotification.Clone(); + break; + case PayloadOneofCase.GetUtxosByAddressesRequest: + GetUtxosByAddressesRequest = other.GetUtxosByAddressesRequest.Clone(); + break; + case PayloadOneofCase.GetUtxosByAddressesResponse: + GetUtxosByAddressesResponse = other.GetUtxosByAddressesResponse.Clone(); + break; + case PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest: + GetVirtualSelectedParentBlueScoreRequest = other.GetVirtualSelectedParentBlueScoreRequest.Clone(); + break; + case PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse: + GetVirtualSelectedParentBlueScoreResponse = other.GetVirtualSelectedParentBlueScoreResponse.Clone(); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest: + NotifyVirtualSelectedParentBlueScoreChangedRequest = other.NotifyVirtualSelectedParentBlueScoreChangedRequest.Clone(); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse: + NotifyVirtualSelectedParentBlueScoreChangedResponse = other.NotifyVirtualSelectedParentBlueScoreChangedResponse.Clone(); + break; + case PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification: + VirtualSelectedParentBlueScoreChangedNotification = other.VirtualSelectedParentBlueScoreChangedNotification.Clone(); + break; + case PayloadOneofCase.BanRequest: + BanRequest = other.BanRequest.Clone(); + break; + case PayloadOneofCase.BanResponse: + BanResponse = other.BanResponse.Clone(); + break; + case PayloadOneofCase.UnbanRequest: + UnbanRequest = other.UnbanRequest.Clone(); + break; + case PayloadOneofCase.UnbanResponse: + UnbanResponse = other.UnbanResponse.Clone(); + break; + case PayloadOneofCase.GetInfoRequest: + GetInfoRequest = other.GetInfoRequest.Clone(); + break; + case PayloadOneofCase.GetInfoResponse: + GetInfoResponse = other.GetInfoResponse.Clone(); + break; + case PayloadOneofCase.StopNotifyingUtxosChangedRequest: + StopNotifyingUtxosChangedRequest = other.StopNotifyingUtxosChangedRequest.Clone(); + break; + case PayloadOneofCase.StopNotifyingUtxosChangedResponse: + StopNotifyingUtxosChangedResponse = other.StopNotifyingUtxosChangedResponse.Clone(); + break; + case PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest: + NotifyPruningPointUTXOSetOverrideRequest = other.NotifyPruningPointUTXOSetOverrideRequest.Clone(); + break; + case PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse: + NotifyPruningPointUTXOSetOverrideResponse = other.NotifyPruningPointUTXOSetOverrideResponse.Clone(); + break; + case PayloadOneofCase.PruningPointUTXOSetOverrideNotification: + PruningPointUTXOSetOverrideNotification = other.PruningPointUTXOSetOverrideNotification.Clone(); + break; + case PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest: + StopNotifyingPruningPointUTXOSetOverrideRequest = other.StopNotifyingPruningPointUTXOSetOverrideRequest.Clone(); + break; + case PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse: + StopNotifyingPruningPointUTXOSetOverrideResponse = other.StopNotifyingPruningPointUTXOSetOverrideResponse.Clone(); + break; + case PayloadOneofCase.EstimateNetworkHashesPerSecondRequest: + EstimateNetworkHashesPerSecondRequest = other.EstimateNetworkHashesPerSecondRequest.Clone(); + break; + case PayloadOneofCase.EstimateNetworkHashesPerSecondResponse: + EstimateNetworkHashesPerSecondResponse = other.EstimateNetworkHashesPerSecondResponse.Clone(); + break; + case PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest: + NotifyVirtualDaaScoreChangedRequest = other.NotifyVirtualDaaScoreChangedRequest.Clone(); + break; + case PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse: + NotifyVirtualDaaScoreChangedResponse = other.NotifyVirtualDaaScoreChangedResponse.Clone(); + break; + case PayloadOneofCase.VirtualDaaScoreChangedNotification: + VirtualDaaScoreChangedNotification = other.VirtualDaaScoreChangedNotification.Clone(); + break; + case PayloadOneofCase.GetBalanceByAddressRequest: + GetBalanceByAddressRequest = other.GetBalanceByAddressRequest.Clone(); + break; + case PayloadOneofCase.GetBalanceByAddressResponse: + GetBalanceByAddressResponse = other.GetBalanceByAddressResponse.Clone(); + break; + case PayloadOneofCase.GetBalancesByAddressesRequest: + GetBalancesByAddressesRequest = other.GetBalancesByAddressesRequest.Clone(); + break; + case PayloadOneofCase.GetBalancesByAddressesResponse: + GetBalancesByAddressesResponse = other.GetBalancesByAddressesResponse.Clone(); + break; + case PayloadOneofCase.NotifyNewBlockTemplateRequest: + NotifyNewBlockTemplateRequest = other.NotifyNewBlockTemplateRequest.Clone(); + break; + case PayloadOneofCase.NotifyNewBlockTemplateResponse: + NotifyNewBlockTemplateResponse = other.NotifyNewBlockTemplateResponse.Clone(); + break; + case PayloadOneofCase.NewBlockTemplateNotification: + NewBlockTemplateNotification = other.NewBlockTemplateNotification.Clone(); + break; + case PayloadOneofCase.GetMempoolEntriesByAddressesRequest: + GetMempoolEntriesByAddressesRequest = other.GetMempoolEntriesByAddressesRequest.Clone(); + break; + case PayloadOneofCase.GetMempoolEntriesByAddressesResponse: + GetMempoolEntriesByAddressesResponse = other.GetMempoolEntriesByAddressesResponse.Clone(); + break; + case PayloadOneofCase.GetCoinSupplyRequest: + GetCoinSupplyRequest = other.GetCoinSupplyRequest.Clone(); + break; + case PayloadOneofCase.GetCoinSupplyResponse: + GetCoinSupplyResponse = other.GetCoinSupplyResponse.Clone(); + break; + } + + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public KaspadMessage Clone() { + return new KaspadMessage(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.AddressesMessage Addresses { + get { return payloadCase_ == PayloadOneofCase.Addresses ? (global::Miningcore.Blockchain.Kaspa.Kaspad.AddressesMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Addresses; + } + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 2; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage Block { + get { return payloadCase_ == PayloadOneofCase.Block ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Block; + } + } + + /// Field number for the "transaction" field. + public const int TransactionFieldNumber = 3; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage Transaction { + get { return payloadCase_ == PayloadOneofCase.Transaction ? (global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Transaction; + } + } + + /// Field number for the "blockLocator" field. + public const int BlockLocatorFieldNumber = 5; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLocatorMessage BlockLocator { + get { return payloadCase_ == PayloadOneofCase.BlockLocator ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLocatorMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BlockLocator; + } + } + + /// Field number for the "requestAddresses" field. + public const int RequestAddressesFieldNumber = 6; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAddressesMessage RequestAddresses { + get { return payloadCase_ == PayloadOneofCase.RequestAddresses ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAddressesMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestAddresses; + } + } + + /// Field number for the "requestRelayBlocks" field. + public const int RequestRelayBlocksFieldNumber = 10; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestRelayBlocksMessage RequestRelayBlocks { + get { return payloadCase_ == PayloadOneofCase.RequestRelayBlocks ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestRelayBlocksMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestRelayBlocks; + } + } + + /// Field number for the "requestTransactions" field. + public const int RequestTransactionsFieldNumber = 12; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestTransactionsMessage RequestTransactions { + get { return payloadCase_ == PayloadOneofCase.RequestTransactions ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestTransactionsMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestTransactions; + } + } + + /// Field number for the "ibdBlock" field. + public const int IbdBlockFieldNumber = 13; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage IbdBlock { + get { return payloadCase_ == PayloadOneofCase.IbdBlock ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.IbdBlock; + } + } + + /// Field number for the "invRelayBlock" field. + public const int InvRelayBlockFieldNumber = 14; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.InvRelayBlockMessage InvRelayBlock { + get { return payloadCase_ == PayloadOneofCase.InvRelayBlock ? (global::Miningcore.Blockchain.Kaspa.Kaspad.InvRelayBlockMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.InvRelayBlock; + } + } + + /// Field number for the "invTransactions" field. + public const int InvTransactionsFieldNumber = 15; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.InvTransactionsMessage InvTransactions { + get { return payloadCase_ == PayloadOneofCase.InvTransactions ? (global::Miningcore.Blockchain.Kaspa.Kaspad.InvTransactionsMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.InvTransactions; + } + } + + /// Field number for the "ping" field. + public const int PingFieldNumber = 16; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.PingMessage Ping { + get { return payloadCase_ == PayloadOneofCase.Ping ? (global::Miningcore.Blockchain.Kaspa.Kaspad.PingMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Ping; + } + } + + /// Field number for the "pong" field. + public const int PongFieldNumber = 17; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.PongMessage Pong { + get { return payloadCase_ == PayloadOneofCase.Pong ? (global::Miningcore.Blockchain.Kaspa.Kaspad.PongMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Pong; + } + } + + /// Field number for the "verack" field. + public const int VerackFieldNumber = 19; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.VerackMessage Verack { + get { return payloadCase_ == PayloadOneofCase.Verack ? (global::Miningcore.Blockchain.Kaspa.Kaspad.VerackMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Verack; + } + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 20; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.VersionMessage Version { + get { return payloadCase_ == PayloadOneofCase.Version ? (global::Miningcore.Blockchain.Kaspa.Kaspad.VersionMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Version; + } + } + + /// Field number for the "transactionNotFound" field. + public const int TransactionNotFoundFieldNumber = 21; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionNotFoundMessage TransactionNotFound { + get { return payloadCase_ == PayloadOneofCase.TransactionNotFound ? (global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionNotFoundMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.TransactionNotFound; + } + } + + /// Field number for the "reject" field. + public const int RejectFieldNumber = 22; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RejectMessage Reject { + get { return payloadCase_ == PayloadOneofCase.Reject ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RejectMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Reject; + } + } + + /// Field number for the "pruningPointUtxoSetChunk" field. + public const int PruningPointUtxoSetChunkFieldNumber = 25; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUtxoSetChunkMessage PruningPointUtxoSetChunk { + get { return payloadCase_ == PayloadOneofCase.PruningPointUtxoSetChunk ? (global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUtxoSetChunkMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.PruningPointUtxoSetChunk; + } + } + + /// Field number for the "requestIBDBlocks" field. + public const int RequestIBDBlocksFieldNumber = 26; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDBlocksMessage RequestIBDBlocks { + get { return payloadCase_ == PayloadOneofCase.RequestIBDBlocks ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDBlocksMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestIBDBlocks; + } + } + + /// Field number for the "unexpectedPruningPoint" field. + public const int UnexpectedPruningPointFieldNumber = 27; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.UnexpectedPruningPointMessage UnexpectedPruningPoint { + get { return payloadCase_ == PayloadOneofCase.UnexpectedPruningPoint ? (global::Miningcore.Blockchain.Kaspa.Kaspad.UnexpectedPruningPointMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.UnexpectedPruningPoint; + } + } + + /// Field number for the "ibdBlockLocator" field. + public const int IbdBlockLocatorFieldNumber = 30; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorMessage IbdBlockLocator { + get { return payloadCase_ == PayloadOneofCase.IbdBlockLocator ? (global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.IbdBlockLocator; + } + } + + /// Field number for the "ibdBlockLocatorHighestHash" field. + public const int IbdBlockLocatorHighestHashFieldNumber = 31; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashMessage IbdBlockLocatorHighestHash { + get { return payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHash ? (global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.IbdBlockLocatorHighestHash; + } + } + + /// Field number for the "requestNextPruningPointUtxoSetChunk" field. + public const int RequestNextPruningPointUtxoSetChunkFieldNumber = 33; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointUtxoSetChunkMessage RequestNextPruningPointUtxoSetChunk { + get { return payloadCase_ == PayloadOneofCase.RequestNextPruningPointUtxoSetChunk ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointUtxoSetChunkMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestNextPruningPointUtxoSetChunk; + } + } + + /// Field number for the "donePruningPointUtxoSetChunks" field. + public const int DonePruningPointUtxoSetChunksFieldNumber = 34; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.DonePruningPointUtxoSetChunksMessage DonePruningPointUtxoSetChunks { + get { return payloadCase_ == PayloadOneofCase.DonePruningPointUtxoSetChunks ? (global::Miningcore.Blockchain.Kaspa.Kaspad.DonePruningPointUtxoSetChunksMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.DonePruningPointUtxoSetChunks; + } + } + + /// Field number for the "ibdBlockLocatorHighestHashNotFound" field. + public const int IbdBlockLocatorHighestHashNotFoundFieldNumber = 35; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashNotFoundMessage IbdBlockLocatorHighestHashNotFound { + get { return payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHashNotFound ? (global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashNotFoundMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.IbdBlockLocatorHighestHashNotFound; + } + } + + /// Field number for the "blockWithTrustedData" field. + public const int BlockWithTrustedDataFieldNumber = 36; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataMessage BlockWithTrustedData { + get { return payloadCase_ == PayloadOneofCase.BlockWithTrustedData ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BlockWithTrustedData; + } + } + + /// Field number for the "doneBlocksWithTrustedData" field. + public const int DoneBlocksWithTrustedDataFieldNumber = 37; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.DoneBlocksWithTrustedDataMessage DoneBlocksWithTrustedData { + get { return payloadCase_ == PayloadOneofCase.DoneBlocksWithTrustedData ? (global::Miningcore.Blockchain.Kaspa.Kaspad.DoneBlocksWithTrustedDataMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.DoneBlocksWithTrustedData; + } + } + + /// Field number for the "requestPruningPointAndItsAnticone" field. + public const int RequestPruningPointAndItsAnticoneFieldNumber = 40; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointAndItsAnticoneMessage RequestPruningPointAndItsAnticone { + get { return payloadCase_ == PayloadOneofCase.RequestPruningPointAndItsAnticone ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointAndItsAnticoneMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestPruningPointAndItsAnticone; + } + } + + /// Field number for the "blockHeaders" field. + public const int BlockHeadersFieldNumber = 41; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeadersMessage BlockHeaders { + get { return payloadCase_ == PayloadOneofCase.BlockHeaders ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeadersMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BlockHeaders; + } + } + + /// Field number for the "requestNextHeaders" field. + public const int RequestNextHeadersFieldNumber = 42; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextHeadersMessage RequestNextHeaders { + get { return payloadCase_ == PayloadOneofCase.RequestNextHeaders ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextHeadersMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestNextHeaders; + } + } + + /// Field number for the "DoneHeaders" field. + public const int DoneHeadersFieldNumber = 43; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.DoneHeadersMessage DoneHeaders { + get { return payloadCase_ == PayloadOneofCase.DoneHeaders ? (global::Miningcore.Blockchain.Kaspa.Kaspad.DoneHeadersMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.DoneHeaders; + } + } + + /// Field number for the "requestPruningPointUTXOSet" field. + public const int RequestPruningPointUTXOSetFieldNumber = 44; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointUTXOSetMessage RequestPruningPointUTXOSet { + get { return payloadCase_ == PayloadOneofCase.RequestPruningPointUTXOSet ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointUTXOSetMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestPruningPointUTXOSet; + } + } + + /// Field number for the "requestHeaders" field. + public const int RequestHeadersFieldNumber = 45; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestHeadersMessage RequestHeaders { + get { return payloadCase_ == PayloadOneofCase.RequestHeaders ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestHeadersMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestHeaders; + } + } + + /// Field number for the "requestBlockLocator" field. + public const int RequestBlockLocatorFieldNumber = 46; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestBlockLocatorMessage RequestBlockLocator { + get { return payloadCase_ == PayloadOneofCase.RequestBlockLocator ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestBlockLocatorMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestBlockLocator; + } + } + + /// Field number for the "pruningPoints" field. + public const int PruningPointsFieldNumber = 47; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointsMessage PruningPoints { + get { return payloadCase_ == PayloadOneofCase.PruningPoints ? (global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointsMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.PruningPoints; + } + } + + /// Field number for the "requestPruningPointProof" field. + public const int RequestPruningPointProofFieldNumber = 48; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointProofMessage RequestPruningPointProof { + get { return payloadCase_ == PayloadOneofCase.RequestPruningPointProof ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointProofMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestPruningPointProof; + } + } + + /// Field number for the "pruningPointProof" field. + public const int PruningPointProofFieldNumber = 49; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofMessage PruningPointProof { + get { return payloadCase_ == PayloadOneofCase.PruningPointProof ? (global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.PruningPointProof; + } + } + + /// Field number for the "ready" field. + public const int ReadyFieldNumber = 50; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.ReadyMessage Ready { + get { return payloadCase_ == PayloadOneofCase.Ready ? (global::Miningcore.Blockchain.Kaspa.Kaspad.ReadyMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.Ready; + } + } + + /// Field number for the "blockWithTrustedDataV4" field. + public const int BlockWithTrustedDataV4FieldNumber = 51; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataV4Message BlockWithTrustedDataV4 { + get { return payloadCase_ == PayloadOneofCase.BlockWithTrustedDataV4 ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataV4Message) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BlockWithTrustedDataV4; + } + } + + /// Field number for the "trustedData" field. + public const int TrustedDataFieldNumber = 52; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.TrustedDataMessage TrustedData { + get { return payloadCase_ == PayloadOneofCase.TrustedData ? (global::Miningcore.Blockchain.Kaspa.Kaspad.TrustedDataMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.TrustedData; + } + } + + /// Field number for the "requestIBDChainBlockLocator" field. + public const int RequestIBDChainBlockLocatorFieldNumber = 53; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDChainBlockLocatorMessage RequestIBDChainBlockLocator { + get { return payloadCase_ == PayloadOneofCase.RequestIBDChainBlockLocator ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDChainBlockLocatorMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestIBDChainBlockLocator; + } + } + + /// Field number for the "ibdChainBlockLocator" field. + public const int IbdChainBlockLocatorFieldNumber = 54; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.IbdChainBlockLocatorMessage IbdChainBlockLocator { + get { return payloadCase_ == PayloadOneofCase.IbdChainBlockLocator ? (global::Miningcore.Blockchain.Kaspa.Kaspad.IbdChainBlockLocatorMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.IbdChainBlockLocator; + } + } + + /// Field number for the "requestAnticone" field. + public const int RequestAnticoneFieldNumber = 55; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAnticoneMessage RequestAnticone { + get { return payloadCase_ == PayloadOneofCase.RequestAnticone ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAnticoneMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestAnticone; + } + } + + /// Field number for the "requestNextPruningPointAndItsAnticoneBlocks" field. + public const int RequestNextPruningPointAndItsAnticoneBlocksFieldNumber = 56; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointAndItsAnticoneBlocksMessage RequestNextPruningPointAndItsAnticoneBlocks { + get { return payloadCase_ == PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks ? (global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointAndItsAnticoneBlocksMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks; + } + } + + /// Field number for the "getCurrentNetworkRequest" field. + public const int GetCurrentNetworkRequestFieldNumber = 1001; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkRequestMessage GetCurrentNetworkRequest { + get { return payloadCase_ == PayloadOneofCase.GetCurrentNetworkRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetCurrentNetworkRequest; + } + } + + /// Field number for the "getCurrentNetworkResponse" field. + public const int GetCurrentNetworkResponseFieldNumber = 1002; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkResponseMessage GetCurrentNetworkResponse { + get { return payloadCase_ == PayloadOneofCase.GetCurrentNetworkResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetCurrentNetworkResponse; + } + } + + /// Field number for the "submitBlockRequest" field. + public const int SubmitBlockRequestFieldNumber = 1003; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockRequestMessage SubmitBlockRequest { + get { return payloadCase_ == PayloadOneofCase.SubmitBlockRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SubmitBlockRequest; + } + } + + /// Field number for the "submitBlockResponse" field. + public const int SubmitBlockResponseFieldNumber = 1004; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage SubmitBlockResponse { + get { return payloadCase_ == PayloadOneofCase.SubmitBlockResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SubmitBlockResponse; + } + } + + /// Field number for the "getBlockTemplateRequest" field. + public const int GetBlockTemplateRequestFieldNumber = 1005; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateRequestMessage GetBlockTemplateRequest { + get { return payloadCase_ == PayloadOneofCase.GetBlockTemplateRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockTemplateRequest; + } + } + + /// Field number for the "getBlockTemplateResponse" field. + public const int GetBlockTemplateResponseFieldNumber = 1006; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateResponseMessage GetBlockTemplateResponse { + get { return payloadCase_ == PayloadOneofCase.GetBlockTemplateResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockTemplateResponse; + } + } + + /// Field number for the "notifyBlockAddedRequest" field. + public const int NotifyBlockAddedRequestFieldNumber = 1007; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedRequestMessage NotifyBlockAddedRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyBlockAddedRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyBlockAddedRequest; + } + } + + /// Field number for the "notifyBlockAddedResponse" field. + public const int NotifyBlockAddedResponseFieldNumber = 1008; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedResponseMessage NotifyBlockAddedResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyBlockAddedResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyBlockAddedResponse; + } + } + + /// Field number for the "blockAddedNotification" field. + public const int BlockAddedNotificationFieldNumber = 1009; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockAddedNotificationMessage BlockAddedNotification { + get { return payloadCase_ == PayloadOneofCase.BlockAddedNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BlockAddedNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BlockAddedNotification; + } + } + + /// Field number for the "getPeerAddressesRequest" field. + public const int GetPeerAddressesRequestFieldNumber = 1010; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesRequestMessage GetPeerAddressesRequest { + get { return payloadCase_ == PayloadOneofCase.GetPeerAddressesRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetPeerAddressesRequest; + } + } + + /// Field number for the "getPeerAddressesResponse" field. + public const int GetPeerAddressesResponseFieldNumber = 1011; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesResponseMessage GetPeerAddressesResponse { + get { return payloadCase_ == PayloadOneofCase.GetPeerAddressesResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetPeerAddressesResponse; + } + } + + /// Field number for the "getSelectedTipHashRequest" field. + public const int GetSelectedTipHashRequestFieldNumber = 1012; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashRequestMessage GetSelectedTipHashRequest { + get { return payloadCase_ == PayloadOneofCase.GetSelectedTipHashRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetSelectedTipHashRequest; + } + } + + /// Field number for the "getSelectedTipHashResponse" field. + public const int GetSelectedTipHashResponseFieldNumber = 1013; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashResponseMessage GetSelectedTipHashResponse { + get { return payloadCase_ == PayloadOneofCase.GetSelectedTipHashResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetSelectedTipHashResponse; + } + } + + /// Field number for the "getMempoolEntryRequest" field. + public const int GetMempoolEntryRequestFieldNumber = 1014; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryRequestMessage GetMempoolEntryRequest { + get { return payloadCase_ == PayloadOneofCase.GetMempoolEntryRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetMempoolEntryRequest; + } + } + + /// Field number for the "getMempoolEntryResponse" field. + public const int GetMempoolEntryResponseFieldNumber = 1015; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryResponseMessage GetMempoolEntryResponse { + get { return payloadCase_ == PayloadOneofCase.GetMempoolEntryResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetMempoolEntryResponse; + } + } + + /// Field number for the "getConnectedPeerInfoRequest" field. + public const int GetConnectedPeerInfoRequestFieldNumber = 1016; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoRequestMessage GetConnectedPeerInfoRequest { + get { return payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetConnectedPeerInfoRequest; + } + } + + /// Field number for the "getConnectedPeerInfoResponse" field. + public const int GetConnectedPeerInfoResponseFieldNumber = 1017; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoResponseMessage GetConnectedPeerInfoResponse { + get { return payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetConnectedPeerInfoResponse; + } + } + + /// Field number for the "addPeerRequest" field. + public const int AddPeerRequestFieldNumber = 1018; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerRequestMessage AddPeerRequest { + get { return payloadCase_ == PayloadOneofCase.AddPeerRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.AddPeerRequest; + } + } + + /// Field number for the "addPeerResponse" field. + public const int AddPeerResponseFieldNumber = 1019; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerResponseMessage AddPeerResponse { + get { return payloadCase_ == PayloadOneofCase.AddPeerResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.AddPeerResponse; + } + } + + /// Field number for the "submitTransactionRequest" field. + public const int SubmitTransactionRequestFieldNumber = 1020; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionRequestMessage SubmitTransactionRequest { + get { return payloadCase_ == PayloadOneofCase.SubmitTransactionRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SubmitTransactionRequest; + } + } + + /// Field number for the "submitTransactionResponse" field. + public const int SubmitTransactionResponseFieldNumber = 1021; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionResponseMessage SubmitTransactionResponse { + get { return payloadCase_ == PayloadOneofCase.SubmitTransactionResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.SubmitTransactionResponse; + } + } + + /// Field number for the "notifyVirtualSelectedParentChainChangedRequest" field. + public const int NotifyVirtualSelectedParentChainChangedRequestFieldNumber = 1022; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedRequestMessage NotifyVirtualSelectedParentChainChangedRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest; + } + } + + /// Field number for the "notifyVirtualSelectedParentChainChangedResponse" field. + public const int NotifyVirtualSelectedParentChainChangedResponseFieldNumber = 1023; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedResponseMessage NotifyVirtualSelectedParentChainChangedResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse; + } + } + + /// Field number for the "virtualSelectedParentChainChangedNotification" field. + public const int VirtualSelectedParentChainChangedNotificationFieldNumber = 1024; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentChainChangedNotificationMessage VirtualSelectedParentChainChangedNotification { + get { return payloadCase_ == PayloadOneofCase.VirtualSelectedParentChainChangedNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentChainChangedNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.VirtualSelectedParentChainChangedNotification; + } + } + + /// Field number for the "getBlockRequest" field. + public const int GetBlockRequestFieldNumber = 1025; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockRequestMessage GetBlockRequest { + get { return payloadCase_ == PayloadOneofCase.GetBlockRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockRequest; + } + } + + /// Field number for the "getBlockResponse" field. + public const int GetBlockResponseFieldNumber = 1026; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockResponseMessage GetBlockResponse { + get { return payloadCase_ == PayloadOneofCase.GetBlockResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockResponse; + } + } + + /// Field number for the "getSubnetworkRequest" field. + public const int GetSubnetworkRequestFieldNumber = 1027; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkRequestMessage GetSubnetworkRequest { + get { return payloadCase_ == PayloadOneofCase.GetSubnetworkRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetSubnetworkRequest; + } + } + + /// Field number for the "getSubnetworkResponse" field. + public const int GetSubnetworkResponseFieldNumber = 1028; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkResponseMessage GetSubnetworkResponse { + get { return payloadCase_ == PayloadOneofCase.GetSubnetworkResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetSubnetworkResponse; + } + } + + /// Field number for the "getVirtualSelectedParentChainFromBlockRequest" field. + public const int GetVirtualSelectedParentChainFromBlockRequestFieldNumber = 1029; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockRequestMessage GetVirtualSelectedParentChainFromBlockRequest { + get { return payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest; + } + } + + /// Field number for the "getVirtualSelectedParentChainFromBlockResponse" field. + public const int GetVirtualSelectedParentChainFromBlockResponseFieldNumber = 1030; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockResponseMessage GetVirtualSelectedParentChainFromBlockResponse { + get { return payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse; + } + } + + /// Field number for the "getBlocksRequest" field. + public const int GetBlocksRequestFieldNumber = 1031; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksRequestMessage GetBlocksRequest { + get { return payloadCase_ == PayloadOneofCase.GetBlocksRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlocksRequest; + } + } + + /// Field number for the "getBlocksResponse" field. + public const int GetBlocksResponseFieldNumber = 1032; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksResponseMessage GetBlocksResponse { + get { return payloadCase_ == PayloadOneofCase.GetBlocksResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlocksResponse; + } + } + + /// Field number for the "getBlockCountRequest" field. + public const int GetBlockCountRequestFieldNumber = 1033; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountRequestMessage GetBlockCountRequest { + get { return payloadCase_ == PayloadOneofCase.GetBlockCountRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockCountRequest; + } + } + + /// Field number for the "getBlockCountResponse" field. + public const int GetBlockCountResponseFieldNumber = 1034; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountResponseMessage GetBlockCountResponse { + get { return payloadCase_ == PayloadOneofCase.GetBlockCountResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockCountResponse; + } + } + + /// Field number for the "getBlockDagInfoRequest" field. + public const int GetBlockDagInfoRequestFieldNumber = 1035; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoRequestMessage GetBlockDagInfoRequest { + get { return payloadCase_ == PayloadOneofCase.GetBlockDagInfoRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockDagInfoRequest; + } + } + + /// Field number for the "getBlockDagInfoResponse" field. + public const int GetBlockDagInfoResponseFieldNumber = 1036; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoResponseMessage GetBlockDagInfoResponse { + get { return payloadCase_ == PayloadOneofCase.GetBlockDagInfoResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBlockDagInfoResponse; + } + } + + /// Field number for the "resolveFinalityConflictRequest" field. + public const int ResolveFinalityConflictRequestFieldNumber = 1037; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictRequestMessage ResolveFinalityConflictRequest { + get { return payloadCase_ == PayloadOneofCase.ResolveFinalityConflictRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ResolveFinalityConflictRequest; + } + } + + /// Field number for the "resolveFinalityConflictResponse" field. + public const int ResolveFinalityConflictResponseFieldNumber = 1038; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictResponseMessage ResolveFinalityConflictResponse { + get { return payloadCase_ == PayloadOneofCase.ResolveFinalityConflictResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ResolveFinalityConflictResponse; + } + } + + /// Field number for the "notifyFinalityConflictsRequest" field. + public const int NotifyFinalityConflictsRequestFieldNumber = 1039; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsRequestMessage NotifyFinalityConflictsRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyFinalityConflictsRequest; + } + } + + /// Field number for the "notifyFinalityConflictsResponse" field. + public const int NotifyFinalityConflictsResponseFieldNumber = 1040; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsResponseMessage NotifyFinalityConflictsResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyFinalityConflictsResponse; + } + } + + /// Field number for the "finalityConflictNotification" field. + public const int FinalityConflictNotificationFieldNumber = 1041; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictNotificationMessage FinalityConflictNotification { + get { return payloadCase_ == PayloadOneofCase.FinalityConflictNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.FinalityConflictNotification; + } + } + + /// Field number for the "finalityConflictResolvedNotification" field. + public const int FinalityConflictResolvedNotificationFieldNumber = 1042; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictResolvedNotificationMessage FinalityConflictResolvedNotification { + get { return payloadCase_ == PayloadOneofCase.FinalityConflictResolvedNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictResolvedNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.FinalityConflictResolvedNotification; + } + } + + /// Field number for the "getMempoolEntriesRequest" field. + public const int GetMempoolEntriesRequestFieldNumber = 1043; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesRequestMessage GetMempoolEntriesRequest { + get { return payloadCase_ == PayloadOneofCase.GetMempoolEntriesRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetMempoolEntriesRequest; + } + } + + /// Field number for the "getMempoolEntriesResponse" field. + public const int GetMempoolEntriesResponseFieldNumber = 1044; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesResponseMessage GetMempoolEntriesResponse { + get { return payloadCase_ == PayloadOneofCase.GetMempoolEntriesResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetMempoolEntriesResponse; + } + } + + /// Field number for the "shutDownRequest" field. + public const int ShutDownRequestFieldNumber = 1045; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownRequestMessage ShutDownRequest { + get { return payloadCase_ == PayloadOneofCase.ShutDownRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ShutDownRequest; + } + } + + /// Field number for the "shutDownResponse" field. + public const int ShutDownResponseFieldNumber = 1046; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownResponseMessage ShutDownResponse { + get { return payloadCase_ == PayloadOneofCase.ShutDownResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.ShutDownResponse; + } + } + + /// Field number for the "getHeadersRequest" field. + public const int GetHeadersRequestFieldNumber = 1047; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersRequestMessage GetHeadersRequest { + get { return payloadCase_ == PayloadOneofCase.GetHeadersRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetHeadersRequest; + } + } + + /// Field number for the "getHeadersResponse" field. + public const int GetHeadersResponseFieldNumber = 1048; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersResponseMessage GetHeadersResponse { + get { return payloadCase_ == PayloadOneofCase.GetHeadersResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetHeadersResponse; + } + } + + /// Field number for the "notifyUtxosChangedRequest" field. + public const int NotifyUtxosChangedRequestFieldNumber = 1049; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedRequestMessage NotifyUtxosChangedRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyUtxosChangedRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyUtxosChangedRequest; + } + } + + /// Field number for the "notifyUtxosChangedResponse" field. + public const int NotifyUtxosChangedResponseFieldNumber = 1050; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedResponseMessage NotifyUtxosChangedResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyUtxosChangedResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyUtxosChangedResponse; + } + } + + /// Field number for the "utxosChangedNotification" field. + public const int UtxosChangedNotificationFieldNumber = 1051; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosChangedNotificationMessage UtxosChangedNotification { + get { return payloadCase_ == PayloadOneofCase.UtxosChangedNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosChangedNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.UtxosChangedNotification; + } + } + + /// Field number for the "getUtxosByAddressesRequest" field. + public const int GetUtxosByAddressesRequestFieldNumber = 1052; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesRequestMessage GetUtxosByAddressesRequest { + get { return payloadCase_ == PayloadOneofCase.GetUtxosByAddressesRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetUtxosByAddressesRequest; + } + } + + /// Field number for the "getUtxosByAddressesResponse" field. + public const int GetUtxosByAddressesResponseFieldNumber = 1053; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesResponseMessage GetUtxosByAddressesResponse { + get { return payloadCase_ == PayloadOneofCase.GetUtxosByAddressesResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetUtxosByAddressesResponse; + } + } + + /// Field number for the "getVirtualSelectedParentBlueScoreRequest" field. + public const int GetVirtualSelectedParentBlueScoreRequestFieldNumber = 1054; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreRequestMessage GetVirtualSelectedParentBlueScoreRequest { + get { return payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest; + } + } + + /// Field number for the "getVirtualSelectedParentBlueScoreResponse" field. + public const int GetVirtualSelectedParentBlueScoreResponseFieldNumber = 1055; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreResponseMessage GetVirtualSelectedParentBlueScoreResponse { + get { return payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse; + } + } + + /// Field number for the "notifyVirtualSelectedParentBlueScoreChangedRequest" field. + public const int NotifyVirtualSelectedParentBlueScoreChangedRequestFieldNumber = 1056; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage NotifyVirtualSelectedParentBlueScoreChangedRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest; + } + } + + /// Field number for the "notifyVirtualSelectedParentBlueScoreChangedResponse" field. + public const int NotifyVirtualSelectedParentBlueScoreChangedResponseFieldNumber = 1057; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage NotifyVirtualSelectedParentBlueScoreChangedResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse; + } + } + + /// Field number for the "virtualSelectedParentBlueScoreChangedNotification" field. + public const int VirtualSelectedParentBlueScoreChangedNotificationFieldNumber = 1058; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentBlueScoreChangedNotificationMessage VirtualSelectedParentBlueScoreChangedNotification { + get { return payloadCase_ == PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentBlueScoreChangedNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification; + } + } + + /// Field number for the "banRequest" field. + public const int BanRequestFieldNumber = 1059; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BanRequestMessage BanRequest { + get { return payloadCase_ == PayloadOneofCase.BanRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BanRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BanRequest; + } + } + + /// Field number for the "banResponse" field. + public const int BanResponseFieldNumber = 1060; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BanResponseMessage BanResponse { + get { return payloadCase_ == PayloadOneofCase.BanResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.BanResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.BanResponse; + } + } + + /// Field number for the "unbanRequest" field. + public const int UnbanRequestFieldNumber = 1061; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanRequestMessage UnbanRequest { + get { return payloadCase_ == PayloadOneofCase.UnbanRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.UnbanRequest; + } + } + + /// Field number for the "unbanResponse" field. + public const int UnbanResponseFieldNumber = 1062; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanResponseMessage UnbanResponse { + get { return payloadCase_ == PayloadOneofCase.UnbanResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.UnbanResponse; + } + } + + /// Field number for the "getInfoRequest" field. + public const int GetInfoRequestFieldNumber = 1063; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoRequestMessage GetInfoRequest { + get { return payloadCase_ == PayloadOneofCase.GetInfoRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetInfoRequest; + } + } + + /// Field number for the "getInfoResponse" field. + public const int GetInfoResponseFieldNumber = 1064; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoResponseMessage GetInfoResponse { + get { return payloadCase_ == PayloadOneofCase.GetInfoResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetInfoResponse; + } + } + + /// Field number for the "stopNotifyingUtxosChangedRequest" field. + public const int StopNotifyingUtxosChangedRequestFieldNumber = 1065; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedRequestMessage StopNotifyingUtxosChangedRequest { + get { return payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.StopNotifyingUtxosChangedRequest; + } + } + + /// Field number for the "stopNotifyingUtxosChangedResponse" field. + public const int StopNotifyingUtxosChangedResponseFieldNumber = 1066; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedResponseMessage StopNotifyingUtxosChangedResponse { + get { return payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.StopNotifyingUtxosChangedResponse; + } + } + + /// Field number for the "notifyPruningPointUTXOSetOverrideRequest" field. + public const int NotifyPruningPointUTXOSetOverrideRequestFieldNumber = 1067; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideRequestMessage NotifyPruningPointUTXOSetOverrideRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest; + } + } + + /// Field number for the "notifyPruningPointUTXOSetOverrideResponse" field. + public const int NotifyPruningPointUTXOSetOverrideResponseFieldNumber = 1068; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideResponseMessage NotifyPruningPointUTXOSetOverrideResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse; + } + } + + /// Field number for the "pruningPointUTXOSetOverrideNotification" field. + public const int PruningPointUTXOSetOverrideNotificationFieldNumber = 1069; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUTXOSetOverrideNotificationMessage PruningPointUTXOSetOverrideNotification { + get { return payloadCase_ == PayloadOneofCase.PruningPointUTXOSetOverrideNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUTXOSetOverrideNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.PruningPointUTXOSetOverrideNotification; + } + } + + /// Field number for the "stopNotifyingPruningPointUTXOSetOverrideRequest" field. + public const int StopNotifyingPruningPointUTXOSetOverrideRequestFieldNumber = 1070; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideRequestMessage StopNotifyingPruningPointUTXOSetOverrideRequest { + get { return payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest; + } + } + + /// Field number for the "stopNotifyingPruningPointUTXOSetOverrideResponse" field. + public const int StopNotifyingPruningPointUTXOSetOverrideResponseFieldNumber = 1071; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideResponseMessage StopNotifyingPruningPointUTXOSetOverrideResponse { + get { return payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse; + } + } + + /// Field number for the "estimateNetworkHashesPerSecondRequest" field. + public const int EstimateNetworkHashesPerSecondRequestFieldNumber = 1072; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondRequestMessage EstimateNetworkHashesPerSecondRequest { + get { return payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.EstimateNetworkHashesPerSecondRequest; + } + } + + /// Field number for the "estimateNetworkHashesPerSecondResponse" field. + public const int EstimateNetworkHashesPerSecondResponseFieldNumber = 1073; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondResponseMessage EstimateNetworkHashesPerSecondResponse { + get { return payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.EstimateNetworkHashesPerSecondResponse; + } + } + + /// Field number for the "notifyVirtualDaaScoreChangedRequest" field. + public const int NotifyVirtualDaaScoreChangedRequestFieldNumber = 1074; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedRequestMessage NotifyVirtualDaaScoreChangedRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest; + } + } + + /// Field number for the "notifyVirtualDaaScoreChangedResponse" field. + public const int NotifyVirtualDaaScoreChangedResponseFieldNumber = 1075; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedResponseMessage NotifyVirtualDaaScoreChangedResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse; + } + } + + /// Field number for the "virtualDaaScoreChangedNotification" field. + public const int VirtualDaaScoreChangedNotificationFieldNumber = 1076; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualDaaScoreChangedNotificationMessage VirtualDaaScoreChangedNotification { + get { return payloadCase_ == PayloadOneofCase.VirtualDaaScoreChangedNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualDaaScoreChangedNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.VirtualDaaScoreChangedNotification; + } + } + + /// Field number for the "getBalanceByAddressRequest" field. + public const int GetBalanceByAddressRequestFieldNumber = 1077; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressRequestMessage GetBalanceByAddressRequest { + get { return payloadCase_ == PayloadOneofCase.GetBalanceByAddressRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBalanceByAddressRequest; + } + } + + /// Field number for the "getBalanceByAddressResponse" field. + public const int GetBalanceByAddressResponseFieldNumber = 1078; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressResponseMessage GetBalanceByAddressResponse { + get { return payloadCase_ == PayloadOneofCase.GetBalanceByAddressResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBalanceByAddressResponse; + } + } + + /// Field number for the "getBalancesByAddressesRequest" field. + public const int GetBalancesByAddressesRequestFieldNumber = 1079; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesRequestMessage GetBalancesByAddressesRequest { + get { return payloadCase_ == PayloadOneofCase.GetBalancesByAddressesRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBalancesByAddressesRequest; + } + } + + /// Field number for the "getBalancesByAddressesResponse" field. + public const int GetBalancesByAddressesResponseFieldNumber = 1080; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesResponseMessage GetBalancesByAddressesResponse { + get { return payloadCase_ == PayloadOneofCase.GetBalancesByAddressesResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetBalancesByAddressesResponse; + } + } + + /// Field number for the "notifyNewBlockTemplateRequest" field. + public const int NotifyNewBlockTemplateRequestFieldNumber = 1081; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateRequestMessage NotifyNewBlockTemplateRequest { + get { return payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyNewBlockTemplateRequest; + } + } + + /// Field number for the "notifyNewBlockTemplateResponse" field. + public const int NotifyNewBlockTemplateResponseFieldNumber = 1082; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateResponseMessage NotifyNewBlockTemplateResponse { + get { return payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NotifyNewBlockTemplateResponse; + } + } + + /// Field number for the "newBlockTemplateNotification" field. + public const int NewBlockTemplateNotificationFieldNumber = 1083; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NewBlockTemplateNotificationMessage NewBlockTemplateNotification { + get { return payloadCase_ == PayloadOneofCase.NewBlockTemplateNotification ? (global::Miningcore.Blockchain.Kaspa.Kaspad.NewBlockTemplateNotificationMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.NewBlockTemplateNotification; + } + } + + /// Field number for the "getMempoolEntriesByAddressesRequest" field. + public const int GetMempoolEntriesByAddressesRequestFieldNumber = 1084; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesRequestMessage GetMempoolEntriesByAddressesRequest { + get { return payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetMempoolEntriesByAddressesRequest; + } + } + + /// Field number for the "getMempoolEntriesByAddressesResponse" field. + public const int GetMempoolEntriesByAddressesResponseFieldNumber = 1085; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesResponseMessage GetMempoolEntriesByAddressesResponse { + get { return payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetMempoolEntriesByAddressesResponse; + } + } + + /// Field number for the "getCoinSupplyRequest" field. + public const int GetCoinSupplyRequestFieldNumber = 1086; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyRequestMessage GetCoinSupplyRequest { + get { return payloadCase_ == PayloadOneofCase.GetCoinSupplyRequest ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyRequestMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetCoinSupplyRequest; + } + } + + /// Field number for the "getCoinSupplyResponse" field. + public const int GetCoinSupplyResponseFieldNumber = 1087; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyResponseMessage GetCoinSupplyResponse { + get { return payloadCase_ == PayloadOneofCase.GetCoinSupplyResponse ? (global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyResponseMessage) payload_ : null; } + set { + payload_ = value; + payloadCase_ = value == null ? PayloadOneofCase.None : PayloadOneofCase.GetCoinSupplyResponse; + } + } + + private object payload_; + /// Enum of possible cases for the "payload" oneof. + public enum PayloadOneofCase { + None = 0, + Addresses = 1, + Block = 2, + Transaction = 3, + BlockLocator = 5, + RequestAddresses = 6, + RequestRelayBlocks = 10, + RequestTransactions = 12, + IbdBlock = 13, + InvRelayBlock = 14, + InvTransactions = 15, + Ping = 16, + Pong = 17, + Verack = 19, + Version = 20, + TransactionNotFound = 21, + Reject = 22, + PruningPointUtxoSetChunk = 25, + RequestIBDBlocks = 26, + UnexpectedPruningPoint = 27, + IbdBlockLocator = 30, + IbdBlockLocatorHighestHash = 31, + RequestNextPruningPointUtxoSetChunk = 33, + DonePruningPointUtxoSetChunks = 34, + IbdBlockLocatorHighestHashNotFound = 35, + BlockWithTrustedData = 36, + DoneBlocksWithTrustedData = 37, + RequestPruningPointAndItsAnticone = 40, + BlockHeaders = 41, + RequestNextHeaders = 42, + DoneHeaders = 43, + RequestPruningPointUTXOSet = 44, + RequestHeaders = 45, + RequestBlockLocator = 46, + PruningPoints = 47, + RequestPruningPointProof = 48, + PruningPointProof = 49, + Ready = 50, + BlockWithTrustedDataV4 = 51, + TrustedData = 52, + RequestIBDChainBlockLocator = 53, + IbdChainBlockLocator = 54, + RequestAnticone = 55, + RequestNextPruningPointAndItsAnticoneBlocks = 56, + GetCurrentNetworkRequest = 1001, + GetCurrentNetworkResponse = 1002, + SubmitBlockRequest = 1003, + SubmitBlockResponse = 1004, + GetBlockTemplateRequest = 1005, + GetBlockTemplateResponse = 1006, + NotifyBlockAddedRequest = 1007, + NotifyBlockAddedResponse = 1008, + BlockAddedNotification = 1009, + GetPeerAddressesRequest = 1010, + GetPeerAddressesResponse = 1011, + GetSelectedTipHashRequest = 1012, + GetSelectedTipHashResponse = 1013, + GetMempoolEntryRequest = 1014, + GetMempoolEntryResponse = 1015, + GetConnectedPeerInfoRequest = 1016, + GetConnectedPeerInfoResponse = 1017, + AddPeerRequest = 1018, + AddPeerResponse = 1019, + SubmitTransactionRequest = 1020, + SubmitTransactionResponse = 1021, + NotifyVirtualSelectedParentChainChangedRequest = 1022, + NotifyVirtualSelectedParentChainChangedResponse = 1023, + VirtualSelectedParentChainChangedNotification = 1024, + GetBlockRequest = 1025, + GetBlockResponse = 1026, + GetSubnetworkRequest = 1027, + GetSubnetworkResponse = 1028, + GetVirtualSelectedParentChainFromBlockRequest = 1029, + GetVirtualSelectedParentChainFromBlockResponse = 1030, + GetBlocksRequest = 1031, + GetBlocksResponse = 1032, + GetBlockCountRequest = 1033, + GetBlockCountResponse = 1034, + GetBlockDagInfoRequest = 1035, + GetBlockDagInfoResponse = 1036, + ResolveFinalityConflictRequest = 1037, + ResolveFinalityConflictResponse = 1038, + NotifyFinalityConflictsRequest = 1039, + NotifyFinalityConflictsResponse = 1040, + FinalityConflictNotification = 1041, + FinalityConflictResolvedNotification = 1042, + GetMempoolEntriesRequest = 1043, + GetMempoolEntriesResponse = 1044, + ShutDownRequest = 1045, + ShutDownResponse = 1046, + GetHeadersRequest = 1047, + GetHeadersResponse = 1048, + NotifyUtxosChangedRequest = 1049, + NotifyUtxosChangedResponse = 1050, + UtxosChangedNotification = 1051, + GetUtxosByAddressesRequest = 1052, + GetUtxosByAddressesResponse = 1053, + GetVirtualSelectedParentBlueScoreRequest = 1054, + GetVirtualSelectedParentBlueScoreResponse = 1055, + NotifyVirtualSelectedParentBlueScoreChangedRequest = 1056, + NotifyVirtualSelectedParentBlueScoreChangedResponse = 1057, + VirtualSelectedParentBlueScoreChangedNotification = 1058, + BanRequest = 1059, + BanResponse = 1060, + UnbanRequest = 1061, + UnbanResponse = 1062, + GetInfoRequest = 1063, + GetInfoResponse = 1064, + StopNotifyingUtxosChangedRequest = 1065, + StopNotifyingUtxosChangedResponse = 1066, + NotifyPruningPointUTXOSetOverrideRequest = 1067, + NotifyPruningPointUTXOSetOverrideResponse = 1068, + PruningPointUTXOSetOverrideNotification = 1069, + StopNotifyingPruningPointUTXOSetOverrideRequest = 1070, + StopNotifyingPruningPointUTXOSetOverrideResponse = 1071, + EstimateNetworkHashesPerSecondRequest = 1072, + EstimateNetworkHashesPerSecondResponse = 1073, + NotifyVirtualDaaScoreChangedRequest = 1074, + NotifyVirtualDaaScoreChangedResponse = 1075, + VirtualDaaScoreChangedNotification = 1076, + GetBalanceByAddressRequest = 1077, + GetBalanceByAddressResponse = 1078, + GetBalancesByAddressesRequest = 1079, + GetBalancesByAddressesResponse = 1080, + NotifyNewBlockTemplateRequest = 1081, + NotifyNewBlockTemplateResponse = 1082, + NewBlockTemplateNotification = 1083, + GetMempoolEntriesByAddressesRequest = 1084, + GetMempoolEntriesByAddressesResponse = 1085, + GetCoinSupplyRequest = 1086, + GetCoinSupplyResponse = 1087, + } + private PayloadOneofCase payloadCase_ = PayloadOneofCase.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PayloadOneofCase PayloadCase { + get { return payloadCase_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void ClearPayload() { + payloadCase_ = PayloadOneofCase.None; + payload_ = null; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as KaspadMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(KaspadMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Addresses, other.Addresses)) return false; + if (!object.Equals(Block, other.Block)) return false; + if (!object.Equals(Transaction, other.Transaction)) return false; + if (!object.Equals(BlockLocator, other.BlockLocator)) return false; + if (!object.Equals(RequestAddresses, other.RequestAddresses)) return false; + if (!object.Equals(RequestRelayBlocks, other.RequestRelayBlocks)) return false; + if (!object.Equals(RequestTransactions, other.RequestTransactions)) return false; + if (!object.Equals(IbdBlock, other.IbdBlock)) return false; + if (!object.Equals(InvRelayBlock, other.InvRelayBlock)) return false; + if (!object.Equals(InvTransactions, other.InvTransactions)) return false; + if (!object.Equals(Ping, other.Ping)) return false; + if (!object.Equals(Pong, other.Pong)) return false; + if (!object.Equals(Verack, other.Verack)) return false; + if (!object.Equals(Version, other.Version)) return false; + if (!object.Equals(TransactionNotFound, other.TransactionNotFound)) return false; + if (!object.Equals(Reject, other.Reject)) return false; + if (!object.Equals(PruningPointUtxoSetChunk, other.PruningPointUtxoSetChunk)) return false; + if (!object.Equals(RequestIBDBlocks, other.RequestIBDBlocks)) return false; + if (!object.Equals(UnexpectedPruningPoint, other.UnexpectedPruningPoint)) return false; + if (!object.Equals(IbdBlockLocator, other.IbdBlockLocator)) return false; + if (!object.Equals(IbdBlockLocatorHighestHash, other.IbdBlockLocatorHighestHash)) return false; + if (!object.Equals(RequestNextPruningPointUtxoSetChunk, other.RequestNextPruningPointUtxoSetChunk)) return false; + if (!object.Equals(DonePruningPointUtxoSetChunks, other.DonePruningPointUtxoSetChunks)) return false; + if (!object.Equals(IbdBlockLocatorHighestHashNotFound, other.IbdBlockLocatorHighestHashNotFound)) return false; + if (!object.Equals(BlockWithTrustedData, other.BlockWithTrustedData)) return false; + if (!object.Equals(DoneBlocksWithTrustedData, other.DoneBlocksWithTrustedData)) return false; + if (!object.Equals(RequestPruningPointAndItsAnticone, other.RequestPruningPointAndItsAnticone)) return false; + if (!object.Equals(BlockHeaders, other.BlockHeaders)) return false; + if (!object.Equals(RequestNextHeaders, other.RequestNextHeaders)) return false; + if (!object.Equals(DoneHeaders, other.DoneHeaders)) return false; + if (!object.Equals(RequestPruningPointUTXOSet, other.RequestPruningPointUTXOSet)) return false; + if (!object.Equals(RequestHeaders, other.RequestHeaders)) return false; + if (!object.Equals(RequestBlockLocator, other.RequestBlockLocator)) return false; + if (!object.Equals(PruningPoints, other.PruningPoints)) return false; + if (!object.Equals(RequestPruningPointProof, other.RequestPruningPointProof)) return false; + if (!object.Equals(PruningPointProof, other.PruningPointProof)) return false; + if (!object.Equals(Ready, other.Ready)) return false; + if (!object.Equals(BlockWithTrustedDataV4, other.BlockWithTrustedDataV4)) return false; + if (!object.Equals(TrustedData, other.TrustedData)) return false; + if (!object.Equals(RequestIBDChainBlockLocator, other.RequestIBDChainBlockLocator)) return false; + if (!object.Equals(IbdChainBlockLocator, other.IbdChainBlockLocator)) return false; + if (!object.Equals(RequestAnticone, other.RequestAnticone)) return false; + if (!object.Equals(RequestNextPruningPointAndItsAnticoneBlocks, other.RequestNextPruningPointAndItsAnticoneBlocks)) return false; + if (!object.Equals(GetCurrentNetworkRequest, other.GetCurrentNetworkRequest)) return false; + if (!object.Equals(GetCurrentNetworkResponse, other.GetCurrentNetworkResponse)) return false; + if (!object.Equals(SubmitBlockRequest, other.SubmitBlockRequest)) return false; + if (!object.Equals(SubmitBlockResponse, other.SubmitBlockResponse)) return false; + if (!object.Equals(GetBlockTemplateRequest, other.GetBlockTemplateRequest)) return false; + if (!object.Equals(GetBlockTemplateResponse, other.GetBlockTemplateResponse)) return false; + if (!object.Equals(NotifyBlockAddedRequest, other.NotifyBlockAddedRequest)) return false; + if (!object.Equals(NotifyBlockAddedResponse, other.NotifyBlockAddedResponse)) return false; + if (!object.Equals(BlockAddedNotification, other.BlockAddedNotification)) return false; + if (!object.Equals(GetPeerAddressesRequest, other.GetPeerAddressesRequest)) return false; + if (!object.Equals(GetPeerAddressesResponse, other.GetPeerAddressesResponse)) return false; + if (!object.Equals(GetSelectedTipHashRequest, other.GetSelectedTipHashRequest)) return false; + if (!object.Equals(GetSelectedTipHashResponse, other.GetSelectedTipHashResponse)) return false; + if (!object.Equals(GetMempoolEntryRequest, other.GetMempoolEntryRequest)) return false; + if (!object.Equals(GetMempoolEntryResponse, other.GetMempoolEntryResponse)) return false; + if (!object.Equals(GetConnectedPeerInfoRequest, other.GetConnectedPeerInfoRequest)) return false; + if (!object.Equals(GetConnectedPeerInfoResponse, other.GetConnectedPeerInfoResponse)) return false; + if (!object.Equals(AddPeerRequest, other.AddPeerRequest)) return false; + if (!object.Equals(AddPeerResponse, other.AddPeerResponse)) return false; + if (!object.Equals(SubmitTransactionRequest, other.SubmitTransactionRequest)) return false; + if (!object.Equals(SubmitTransactionResponse, other.SubmitTransactionResponse)) return false; + if (!object.Equals(NotifyVirtualSelectedParentChainChangedRequest, other.NotifyVirtualSelectedParentChainChangedRequest)) return false; + if (!object.Equals(NotifyVirtualSelectedParentChainChangedResponse, other.NotifyVirtualSelectedParentChainChangedResponse)) return false; + if (!object.Equals(VirtualSelectedParentChainChangedNotification, other.VirtualSelectedParentChainChangedNotification)) return false; + if (!object.Equals(GetBlockRequest, other.GetBlockRequest)) return false; + if (!object.Equals(GetBlockResponse, other.GetBlockResponse)) return false; + if (!object.Equals(GetSubnetworkRequest, other.GetSubnetworkRequest)) return false; + if (!object.Equals(GetSubnetworkResponse, other.GetSubnetworkResponse)) return false; + if (!object.Equals(GetVirtualSelectedParentChainFromBlockRequest, other.GetVirtualSelectedParentChainFromBlockRequest)) return false; + if (!object.Equals(GetVirtualSelectedParentChainFromBlockResponse, other.GetVirtualSelectedParentChainFromBlockResponse)) return false; + if (!object.Equals(GetBlocksRequest, other.GetBlocksRequest)) return false; + if (!object.Equals(GetBlocksResponse, other.GetBlocksResponse)) return false; + if (!object.Equals(GetBlockCountRequest, other.GetBlockCountRequest)) return false; + if (!object.Equals(GetBlockCountResponse, other.GetBlockCountResponse)) return false; + if (!object.Equals(GetBlockDagInfoRequest, other.GetBlockDagInfoRequest)) return false; + if (!object.Equals(GetBlockDagInfoResponse, other.GetBlockDagInfoResponse)) return false; + if (!object.Equals(ResolveFinalityConflictRequest, other.ResolveFinalityConflictRequest)) return false; + if (!object.Equals(ResolveFinalityConflictResponse, other.ResolveFinalityConflictResponse)) return false; + if (!object.Equals(NotifyFinalityConflictsRequest, other.NotifyFinalityConflictsRequest)) return false; + if (!object.Equals(NotifyFinalityConflictsResponse, other.NotifyFinalityConflictsResponse)) return false; + if (!object.Equals(FinalityConflictNotification, other.FinalityConflictNotification)) return false; + if (!object.Equals(FinalityConflictResolvedNotification, other.FinalityConflictResolvedNotification)) return false; + if (!object.Equals(GetMempoolEntriesRequest, other.GetMempoolEntriesRequest)) return false; + if (!object.Equals(GetMempoolEntriesResponse, other.GetMempoolEntriesResponse)) return false; + if (!object.Equals(ShutDownRequest, other.ShutDownRequest)) return false; + if (!object.Equals(ShutDownResponse, other.ShutDownResponse)) return false; + if (!object.Equals(GetHeadersRequest, other.GetHeadersRequest)) return false; + if (!object.Equals(GetHeadersResponse, other.GetHeadersResponse)) return false; + if (!object.Equals(NotifyUtxosChangedRequest, other.NotifyUtxosChangedRequest)) return false; + if (!object.Equals(NotifyUtxosChangedResponse, other.NotifyUtxosChangedResponse)) return false; + if (!object.Equals(UtxosChangedNotification, other.UtxosChangedNotification)) return false; + if (!object.Equals(GetUtxosByAddressesRequest, other.GetUtxosByAddressesRequest)) return false; + if (!object.Equals(GetUtxosByAddressesResponse, other.GetUtxosByAddressesResponse)) return false; + if (!object.Equals(GetVirtualSelectedParentBlueScoreRequest, other.GetVirtualSelectedParentBlueScoreRequest)) return false; + if (!object.Equals(GetVirtualSelectedParentBlueScoreResponse, other.GetVirtualSelectedParentBlueScoreResponse)) return false; + if (!object.Equals(NotifyVirtualSelectedParentBlueScoreChangedRequest, other.NotifyVirtualSelectedParentBlueScoreChangedRequest)) return false; + if (!object.Equals(NotifyVirtualSelectedParentBlueScoreChangedResponse, other.NotifyVirtualSelectedParentBlueScoreChangedResponse)) return false; + if (!object.Equals(VirtualSelectedParentBlueScoreChangedNotification, other.VirtualSelectedParentBlueScoreChangedNotification)) return false; + if (!object.Equals(BanRequest, other.BanRequest)) return false; + if (!object.Equals(BanResponse, other.BanResponse)) return false; + if (!object.Equals(UnbanRequest, other.UnbanRequest)) return false; + if (!object.Equals(UnbanResponse, other.UnbanResponse)) return false; + if (!object.Equals(GetInfoRequest, other.GetInfoRequest)) return false; + if (!object.Equals(GetInfoResponse, other.GetInfoResponse)) return false; + if (!object.Equals(StopNotifyingUtxosChangedRequest, other.StopNotifyingUtxosChangedRequest)) return false; + if (!object.Equals(StopNotifyingUtxosChangedResponse, other.StopNotifyingUtxosChangedResponse)) return false; + if (!object.Equals(NotifyPruningPointUTXOSetOverrideRequest, other.NotifyPruningPointUTXOSetOverrideRequest)) return false; + if (!object.Equals(NotifyPruningPointUTXOSetOverrideResponse, other.NotifyPruningPointUTXOSetOverrideResponse)) return false; + if (!object.Equals(PruningPointUTXOSetOverrideNotification, other.PruningPointUTXOSetOverrideNotification)) return false; + if (!object.Equals(StopNotifyingPruningPointUTXOSetOverrideRequest, other.StopNotifyingPruningPointUTXOSetOverrideRequest)) return false; + if (!object.Equals(StopNotifyingPruningPointUTXOSetOverrideResponse, other.StopNotifyingPruningPointUTXOSetOverrideResponse)) return false; + if (!object.Equals(EstimateNetworkHashesPerSecondRequest, other.EstimateNetworkHashesPerSecondRequest)) return false; + if (!object.Equals(EstimateNetworkHashesPerSecondResponse, other.EstimateNetworkHashesPerSecondResponse)) return false; + if (!object.Equals(NotifyVirtualDaaScoreChangedRequest, other.NotifyVirtualDaaScoreChangedRequest)) return false; + if (!object.Equals(NotifyVirtualDaaScoreChangedResponse, other.NotifyVirtualDaaScoreChangedResponse)) return false; + if (!object.Equals(VirtualDaaScoreChangedNotification, other.VirtualDaaScoreChangedNotification)) return false; + if (!object.Equals(GetBalanceByAddressRequest, other.GetBalanceByAddressRequest)) return false; + if (!object.Equals(GetBalanceByAddressResponse, other.GetBalanceByAddressResponse)) return false; + if (!object.Equals(GetBalancesByAddressesRequest, other.GetBalancesByAddressesRequest)) return false; + if (!object.Equals(GetBalancesByAddressesResponse, other.GetBalancesByAddressesResponse)) return false; + if (!object.Equals(NotifyNewBlockTemplateRequest, other.NotifyNewBlockTemplateRequest)) return false; + if (!object.Equals(NotifyNewBlockTemplateResponse, other.NotifyNewBlockTemplateResponse)) return false; + if (!object.Equals(NewBlockTemplateNotification, other.NewBlockTemplateNotification)) return false; + if (!object.Equals(GetMempoolEntriesByAddressesRequest, other.GetMempoolEntriesByAddressesRequest)) return false; + if (!object.Equals(GetMempoolEntriesByAddressesResponse, other.GetMempoolEntriesByAddressesResponse)) return false; + if (!object.Equals(GetCoinSupplyRequest, other.GetCoinSupplyRequest)) return false; + if (!object.Equals(GetCoinSupplyResponse, other.GetCoinSupplyResponse)) return false; + if (PayloadCase != other.PayloadCase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (payloadCase_ == PayloadOneofCase.Addresses) hash ^= Addresses.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Block) hash ^= Block.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Transaction) hash ^= Transaction.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.BlockLocator) hash ^= BlockLocator.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestAddresses) hash ^= RequestAddresses.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestRelayBlocks) hash ^= RequestRelayBlocks.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestTransactions) hash ^= RequestTransactions.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.IbdBlock) hash ^= IbdBlock.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.InvRelayBlock) hash ^= InvRelayBlock.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.InvTransactions) hash ^= InvTransactions.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Ping) hash ^= Ping.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Pong) hash ^= Pong.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Verack) hash ^= Verack.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Version) hash ^= Version.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.TransactionNotFound) hash ^= TransactionNotFound.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Reject) hash ^= Reject.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.PruningPointUtxoSetChunk) hash ^= PruningPointUtxoSetChunk.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestIBDBlocks) hash ^= RequestIBDBlocks.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.UnexpectedPruningPoint) hash ^= UnexpectedPruningPoint.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.IbdBlockLocator) hash ^= IbdBlockLocator.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHash) hash ^= IbdBlockLocatorHighestHash.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointUtxoSetChunk) hash ^= RequestNextPruningPointUtxoSetChunk.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.DonePruningPointUtxoSetChunks) hash ^= DonePruningPointUtxoSetChunks.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHashNotFound) hash ^= IbdBlockLocatorHighestHashNotFound.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedData) hash ^= BlockWithTrustedData.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.DoneBlocksWithTrustedData) hash ^= DoneBlocksWithTrustedData.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestPruningPointAndItsAnticone) hash ^= RequestPruningPointAndItsAnticone.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.BlockHeaders) hash ^= BlockHeaders.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestNextHeaders) hash ^= RequestNextHeaders.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.DoneHeaders) hash ^= DoneHeaders.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestPruningPointUTXOSet) hash ^= RequestPruningPointUTXOSet.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestHeaders) hash ^= RequestHeaders.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestBlockLocator) hash ^= RequestBlockLocator.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.PruningPoints) hash ^= PruningPoints.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestPruningPointProof) hash ^= RequestPruningPointProof.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.PruningPointProof) hash ^= PruningPointProof.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.Ready) hash ^= Ready.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedDataV4) hash ^= BlockWithTrustedDataV4.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.TrustedData) hash ^= TrustedData.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestIBDChainBlockLocator) hash ^= RequestIBDChainBlockLocator.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.IbdChainBlockLocator) hash ^= IbdChainBlockLocator.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestAnticone) hash ^= RequestAnticone.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks) hash ^= RequestNextPruningPointAndItsAnticoneBlocks.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkRequest) hash ^= GetCurrentNetworkRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkResponse) hash ^= GetCurrentNetworkResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.SubmitBlockRequest) hash ^= SubmitBlockRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.SubmitBlockResponse) hash ^= SubmitBlockResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateRequest) hash ^= GetBlockTemplateRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateResponse) hash ^= GetBlockTemplateResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedRequest) hash ^= NotifyBlockAddedRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedResponse) hash ^= NotifyBlockAddedResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.BlockAddedNotification) hash ^= BlockAddedNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesRequest) hash ^= GetPeerAddressesRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesResponse) hash ^= GetPeerAddressesResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashRequest) hash ^= GetSelectedTipHashRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashResponse) hash ^= GetSelectedTipHashResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryRequest) hash ^= GetMempoolEntryRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryResponse) hash ^= GetMempoolEntryResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoRequest) hash ^= GetConnectedPeerInfoRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoResponse) hash ^= GetConnectedPeerInfoResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.AddPeerRequest) hash ^= AddPeerRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.AddPeerResponse) hash ^= AddPeerResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.SubmitTransactionRequest) hash ^= SubmitTransactionRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.SubmitTransactionResponse) hash ^= SubmitTransactionResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest) hash ^= NotifyVirtualSelectedParentChainChangedRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse) hash ^= NotifyVirtualSelectedParentChainChangedResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentChainChangedNotification) hash ^= VirtualSelectedParentChainChangedNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockRequest) hash ^= GetBlockRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockResponse) hash ^= GetBlockResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetSubnetworkRequest) hash ^= GetSubnetworkRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetSubnetworkResponse) hash ^= GetSubnetworkResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest) hash ^= GetVirtualSelectedParentChainFromBlockRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse) hash ^= GetVirtualSelectedParentChainFromBlockResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlocksRequest) hash ^= GetBlocksRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlocksResponse) hash ^= GetBlocksResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockCountRequest) hash ^= GetBlockCountRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockCountResponse) hash ^= GetBlockCountResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoRequest) hash ^= GetBlockDagInfoRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoResponse) hash ^= GetBlockDagInfoResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictRequest) hash ^= ResolveFinalityConflictRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictResponse) hash ^= ResolveFinalityConflictResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsRequest) hash ^= NotifyFinalityConflictsRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsResponse) hash ^= NotifyFinalityConflictsResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.FinalityConflictNotification) hash ^= FinalityConflictNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.FinalityConflictResolvedNotification) hash ^= FinalityConflictResolvedNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesRequest) hash ^= GetMempoolEntriesRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesResponse) hash ^= GetMempoolEntriesResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.ShutDownRequest) hash ^= ShutDownRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.ShutDownResponse) hash ^= ShutDownResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetHeadersRequest) hash ^= GetHeadersRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetHeadersResponse) hash ^= GetHeadersResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedRequest) hash ^= NotifyUtxosChangedRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedResponse) hash ^= NotifyUtxosChangedResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.UtxosChangedNotification) hash ^= UtxosChangedNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesRequest) hash ^= GetUtxosByAddressesRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesResponse) hash ^= GetUtxosByAddressesResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest) hash ^= GetVirtualSelectedParentBlueScoreRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse) hash ^= GetVirtualSelectedParentBlueScoreResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest) hash ^= NotifyVirtualSelectedParentBlueScoreChangedRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse) hash ^= NotifyVirtualSelectedParentBlueScoreChangedResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification) hash ^= VirtualSelectedParentBlueScoreChangedNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.BanRequest) hash ^= BanRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.BanResponse) hash ^= BanResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.UnbanRequest) hash ^= UnbanRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.UnbanResponse) hash ^= UnbanResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetInfoRequest) hash ^= GetInfoRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetInfoResponse) hash ^= GetInfoResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedRequest) hash ^= StopNotifyingUtxosChangedRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedResponse) hash ^= StopNotifyingUtxosChangedResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest) hash ^= NotifyPruningPointUTXOSetOverrideRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse) hash ^= NotifyPruningPointUTXOSetOverrideResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.PruningPointUTXOSetOverrideNotification) hash ^= PruningPointUTXOSetOverrideNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest) hash ^= StopNotifyingPruningPointUTXOSetOverrideRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse) hash ^= StopNotifyingPruningPointUTXOSetOverrideResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondRequest) hash ^= EstimateNetworkHashesPerSecondRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondResponse) hash ^= EstimateNetworkHashesPerSecondResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest) hash ^= NotifyVirtualDaaScoreChangedRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse) hash ^= NotifyVirtualDaaScoreChangedResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.VirtualDaaScoreChangedNotification) hash ^= VirtualDaaScoreChangedNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressRequest) hash ^= GetBalanceByAddressRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressResponse) hash ^= GetBalanceByAddressResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesRequest) hash ^= GetBalancesByAddressesRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesResponse) hash ^= GetBalancesByAddressesResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateRequest) hash ^= NotifyNewBlockTemplateRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateResponse) hash ^= NotifyNewBlockTemplateResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.NewBlockTemplateNotification) hash ^= NewBlockTemplateNotification.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesRequest) hash ^= GetMempoolEntriesByAddressesRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesResponse) hash ^= GetMempoolEntriesByAddressesResponse.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyRequest) hash ^= GetCoinSupplyRequest.GetHashCode(); + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyResponse) hash ^= GetCoinSupplyResponse.GetHashCode(); + hash ^= (int) payloadCase_; + 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 (payloadCase_ == PayloadOneofCase.Addresses) { + output.WriteRawTag(10); + output.WriteMessage(Addresses); + } + if (payloadCase_ == PayloadOneofCase.Block) { + output.WriteRawTag(18); + output.WriteMessage(Block); + } + if (payloadCase_ == PayloadOneofCase.Transaction) { + output.WriteRawTag(26); + output.WriteMessage(Transaction); + } + if (payloadCase_ == PayloadOneofCase.BlockLocator) { + output.WriteRawTag(42); + output.WriteMessage(BlockLocator); + } + if (payloadCase_ == PayloadOneofCase.RequestAddresses) { + output.WriteRawTag(50); + output.WriteMessage(RequestAddresses); + } + if (payloadCase_ == PayloadOneofCase.RequestRelayBlocks) { + output.WriteRawTag(82); + output.WriteMessage(RequestRelayBlocks); + } + if (payloadCase_ == PayloadOneofCase.RequestTransactions) { + output.WriteRawTag(98); + output.WriteMessage(RequestTransactions); + } + if (payloadCase_ == PayloadOneofCase.IbdBlock) { + output.WriteRawTag(106); + output.WriteMessage(IbdBlock); + } + if (payloadCase_ == PayloadOneofCase.InvRelayBlock) { + output.WriteRawTag(114); + output.WriteMessage(InvRelayBlock); + } + if (payloadCase_ == PayloadOneofCase.InvTransactions) { + output.WriteRawTag(122); + output.WriteMessage(InvTransactions); + } + if (payloadCase_ == PayloadOneofCase.Ping) { + output.WriteRawTag(130, 1); + output.WriteMessage(Ping); + } + if (payloadCase_ == PayloadOneofCase.Pong) { + output.WriteRawTag(138, 1); + output.WriteMessage(Pong); + } + if (payloadCase_ == PayloadOneofCase.Verack) { + output.WriteRawTag(154, 1); + output.WriteMessage(Verack); + } + if (payloadCase_ == PayloadOneofCase.Version) { + output.WriteRawTag(162, 1); + output.WriteMessage(Version); + } + if (payloadCase_ == PayloadOneofCase.TransactionNotFound) { + output.WriteRawTag(170, 1); + output.WriteMessage(TransactionNotFound); + } + if (payloadCase_ == PayloadOneofCase.Reject) { + output.WriteRawTag(178, 1); + output.WriteMessage(Reject); + } + if (payloadCase_ == PayloadOneofCase.PruningPointUtxoSetChunk) { + output.WriteRawTag(202, 1); + output.WriteMessage(PruningPointUtxoSetChunk); + } + if (payloadCase_ == PayloadOneofCase.RequestIBDBlocks) { + output.WriteRawTag(210, 1); + output.WriteMessage(RequestIBDBlocks); + } + if (payloadCase_ == PayloadOneofCase.UnexpectedPruningPoint) { + output.WriteRawTag(218, 1); + output.WriteMessage(UnexpectedPruningPoint); + } + if (payloadCase_ == PayloadOneofCase.IbdBlockLocator) { + output.WriteRawTag(242, 1); + output.WriteMessage(IbdBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHash) { + output.WriteRawTag(250, 1); + output.WriteMessage(IbdBlockLocatorHighestHash); + } + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointUtxoSetChunk) { + output.WriteRawTag(138, 2); + output.WriteMessage(RequestNextPruningPointUtxoSetChunk); + } + if (payloadCase_ == PayloadOneofCase.DonePruningPointUtxoSetChunks) { + output.WriteRawTag(146, 2); + output.WriteMessage(DonePruningPointUtxoSetChunks); + } + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHashNotFound) { + output.WriteRawTag(154, 2); + output.WriteMessage(IbdBlockLocatorHighestHashNotFound); + } + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedData) { + output.WriteRawTag(162, 2); + output.WriteMessage(BlockWithTrustedData); + } + if (payloadCase_ == PayloadOneofCase.DoneBlocksWithTrustedData) { + output.WriteRawTag(170, 2); + output.WriteMessage(DoneBlocksWithTrustedData); + } + if (payloadCase_ == PayloadOneofCase.RequestPruningPointAndItsAnticone) { + output.WriteRawTag(194, 2); + output.WriteMessage(RequestPruningPointAndItsAnticone); + } + if (payloadCase_ == PayloadOneofCase.BlockHeaders) { + output.WriteRawTag(202, 2); + output.WriteMessage(BlockHeaders); + } + if (payloadCase_ == PayloadOneofCase.RequestNextHeaders) { + output.WriteRawTag(210, 2); + output.WriteMessage(RequestNextHeaders); + } + if (payloadCase_ == PayloadOneofCase.DoneHeaders) { + output.WriteRawTag(218, 2); + output.WriteMessage(DoneHeaders); + } + if (payloadCase_ == PayloadOneofCase.RequestPruningPointUTXOSet) { + output.WriteRawTag(226, 2); + output.WriteMessage(RequestPruningPointUTXOSet); + } + if (payloadCase_ == PayloadOneofCase.RequestHeaders) { + output.WriteRawTag(234, 2); + output.WriteMessage(RequestHeaders); + } + if (payloadCase_ == PayloadOneofCase.RequestBlockLocator) { + output.WriteRawTag(242, 2); + output.WriteMessage(RequestBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.PruningPoints) { + output.WriteRawTag(250, 2); + output.WriteMessage(PruningPoints); + } + if (payloadCase_ == PayloadOneofCase.RequestPruningPointProof) { + output.WriteRawTag(130, 3); + output.WriteMessage(RequestPruningPointProof); + } + if (payloadCase_ == PayloadOneofCase.PruningPointProof) { + output.WriteRawTag(138, 3); + output.WriteMessage(PruningPointProof); + } + if (payloadCase_ == PayloadOneofCase.Ready) { + output.WriteRawTag(146, 3); + output.WriteMessage(Ready); + } + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedDataV4) { + output.WriteRawTag(154, 3); + output.WriteMessage(BlockWithTrustedDataV4); + } + if (payloadCase_ == PayloadOneofCase.TrustedData) { + output.WriteRawTag(162, 3); + output.WriteMessage(TrustedData); + } + if (payloadCase_ == PayloadOneofCase.RequestIBDChainBlockLocator) { + output.WriteRawTag(170, 3); + output.WriteMessage(RequestIBDChainBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.IbdChainBlockLocator) { + output.WriteRawTag(178, 3); + output.WriteMessage(IbdChainBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.RequestAnticone) { + output.WriteRawTag(186, 3); + output.WriteMessage(RequestAnticone); + } + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks) { + output.WriteRawTag(194, 3); + output.WriteMessage(RequestNextPruningPointAndItsAnticoneBlocks); + } + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkRequest) { + output.WriteRawTag(202, 62); + output.WriteMessage(GetCurrentNetworkRequest); + } + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkResponse) { + output.WriteRawTag(210, 62); + output.WriteMessage(GetCurrentNetworkResponse); + } + if (payloadCase_ == PayloadOneofCase.SubmitBlockRequest) { + output.WriteRawTag(218, 62); + output.WriteMessage(SubmitBlockRequest); + } + if (payloadCase_ == PayloadOneofCase.SubmitBlockResponse) { + output.WriteRawTag(226, 62); + output.WriteMessage(SubmitBlockResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateRequest) { + output.WriteRawTag(234, 62); + output.WriteMessage(GetBlockTemplateRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateResponse) { + output.WriteRawTag(242, 62); + output.WriteMessage(GetBlockTemplateResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedRequest) { + output.WriteRawTag(250, 62); + output.WriteMessage(NotifyBlockAddedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedResponse) { + output.WriteRawTag(130, 63); + output.WriteMessage(NotifyBlockAddedResponse); + } + if (payloadCase_ == PayloadOneofCase.BlockAddedNotification) { + output.WriteRawTag(138, 63); + output.WriteMessage(BlockAddedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesRequest) { + output.WriteRawTag(146, 63); + output.WriteMessage(GetPeerAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesResponse) { + output.WriteRawTag(154, 63); + output.WriteMessage(GetPeerAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashRequest) { + output.WriteRawTag(162, 63); + output.WriteMessage(GetSelectedTipHashRequest); + } + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashResponse) { + output.WriteRawTag(170, 63); + output.WriteMessage(GetSelectedTipHashResponse); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryRequest) { + output.WriteRawTag(178, 63); + output.WriteMessage(GetMempoolEntryRequest); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryResponse) { + output.WriteRawTag(186, 63); + output.WriteMessage(GetMempoolEntryResponse); + } + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoRequest) { + output.WriteRawTag(194, 63); + output.WriteMessage(GetConnectedPeerInfoRequest); + } + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoResponse) { + output.WriteRawTag(202, 63); + output.WriteMessage(GetConnectedPeerInfoResponse); + } + if (payloadCase_ == PayloadOneofCase.AddPeerRequest) { + output.WriteRawTag(210, 63); + output.WriteMessage(AddPeerRequest); + } + if (payloadCase_ == PayloadOneofCase.AddPeerResponse) { + output.WriteRawTag(218, 63); + output.WriteMessage(AddPeerResponse); + } + if (payloadCase_ == PayloadOneofCase.SubmitTransactionRequest) { + output.WriteRawTag(226, 63); + output.WriteMessage(SubmitTransactionRequest); + } + if (payloadCase_ == PayloadOneofCase.SubmitTransactionResponse) { + output.WriteRawTag(234, 63); + output.WriteMessage(SubmitTransactionResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest) { + output.WriteRawTag(242, 63); + output.WriteMessage(NotifyVirtualSelectedParentChainChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse) { + output.WriteRawTag(250, 63); + output.WriteMessage(NotifyVirtualSelectedParentChainChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentChainChangedNotification) { + output.WriteRawTag(130, 64); + output.WriteMessage(VirtualSelectedParentChainChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetBlockRequest) { + output.WriteRawTag(138, 64); + output.WriteMessage(GetBlockRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockResponse) { + output.WriteRawTag(146, 64); + output.WriteMessage(GetBlockResponse); + } + if (payloadCase_ == PayloadOneofCase.GetSubnetworkRequest) { + output.WriteRawTag(154, 64); + output.WriteMessage(GetSubnetworkRequest); + } + if (payloadCase_ == PayloadOneofCase.GetSubnetworkResponse) { + output.WriteRawTag(162, 64); + output.WriteMessage(GetSubnetworkResponse); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest) { + output.WriteRawTag(170, 64); + output.WriteMessage(GetVirtualSelectedParentChainFromBlockRequest); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse) { + output.WriteRawTag(178, 64); + output.WriteMessage(GetVirtualSelectedParentChainFromBlockResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlocksRequest) { + output.WriteRawTag(186, 64); + output.WriteMessage(GetBlocksRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlocksResponse) { + output.WriteRawTag(194, 64); + output.WriteMessage(GetBlocksResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlockCountRequest) { + output.WriteRawTag(202, 64); + output.WriteMessage(GetBlockCountRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockCountResponse) { + output.WriteRawTag(210, 64); + output.WriteMessage(GetBlockCountResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoRequest) { + output.WriteRawTag(218, 64); + output.WriteMessage(GetBlockDagInfoRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoResponse) { + output.WriteRawTag(226, 64); + output.WriteMessage(GetBlockDagInfoResponse); + } + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictRequest) { + output.WriteRawTag(234, 64); + output.WriteMessage(ResolveFinalityConflictRequest); + } + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictResponse) { + output.WriteRawTag(242, 64); + output.WriteMessage(ResolveFinalityConflictResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsRequest) { + output.WriteRawTag(250, 64); + output.WriteMessage(NotifyFinalityConflictsRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsResponse) { + output.WriteRawTag(130, 65); + output.WriteMessage(NotifyFinalityConflictsResponse); + } + if (payloadCase_ == PayloadOneofCase.FinalityConflictNotification) { + output.WriteRawTag(138, 65); + output.WriteMessage(FinalityConflictNotification); + } + if (payloadCase_ == PayloadOneofCase.FinalityConflictResolvedNotification) { + output.WriteRawTag(146, 65); + output.WriteMessage(FinalityConflictResolvedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesRequest) { + output.WriteRawTag(154, 65); + output.WriteMessage(GetMempoolEntriesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesResponse) { + output.WriteRawTag(162, 65); + output.WriteMessage(GetMempoolEntriesResponse); + } + if (payloadCase_ == PayloadOneofCase.ShutDownRequest) { + output.WriteRawTag(170, 65); + output.WriteMessage(ShutDownRequest); + } + if (payloadCase_ == PayloadOneofCase.ShutDownResponse) { + output.WriteRawTag(178, 65); + output.WriteMessage(ShutDownResponse); + } + if (payloadCase_ == PayloadOneofCase.GetHeadersRequest) { + output.WriteRawTag(186, 65); + output.WriteMessage(GetHeadersRequest); + } + if (payloadCase_ == PayloadOneofCase.GetHeadersResponse) { + output.WriteRawTag(194, 65); + output.WriteMessage(GetHeadersResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedRequest) { + output.WriteRawTag(202, 65); + output.WriteMessage(NotifyUtxosChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedResponse) { + output.WriteRawTag(210, 65); + output.WriteMessage(NotifyUtxosChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.UtxosChangedNotification) { + output.WriteRawTag(218, 65); + output.WriteMessage(UtxosChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesRequest) { + output.WriteRawTag(226, 65); + output.WriteMessage(GetUtxosByAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesResponse) { + output.WriteRawTag(234, 65); + output.WriteMessage(GetUtxosByAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest) { + output.WriteRawTag(242, 65); + output.WriteMessage(GetVirtualSelectedParentBlueScoreRequest); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse) { + output.WriteRawTag(250, 65); + output.WriteMessage(GetVirtualSelectedParentBlueScoreResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest) { + output.WriteRawTag(130, 66); + output.WriteMessage(NotifyVirtualSelectedParentBlueScoreChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse) { + output.WriteRawTag(138, 66); + output.WriteMessage(NotifyVirtualSelectedParentBlueScoreChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification) { + output.WriteRawTag(146, 66); + output.WriteMessage(VirtualSelectedParentBlueScoreChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.BanRequest) { + output.WriteRawTag(154, 66); + output.WriteMessage(BanRequest); + } + if (payloadCase_ == PayloadOneofCase.BanResponse) { + output.WriteRawTag(162, 66); + output.WriteMessage(BanResponse); + } + if (payloadCase_ == PayloadOneofCase.UnbanRequest) { + output.WriteRawTag(170, 66); + output.WriteMessage(UnbanRequest); + } + if (payloadCase_ == PayloadOneofCase.UnbanResponse) { + output.WriteRawTag(178, 66); + output.WriteMessage(UnbanResponse); + } + if (payloadCase_ == PayloadOneofCase.GetInfoRequest) { + output.WriteRawTag(186, 66); + output.WriteMessage(GetInfoRequest); + } + if (payloadCase_ == PayloadOneofCase.GetInfoResponse) { + output.WriteRawTag(194, 66); + output.WriteMessage(GetInfoResponse); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedRequest) { + output.WriteRawTag(202, 66); + output.WriteMessage(StopNotifyingUtxosChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedResponse) { + output.WriteRawTag(210, 66); + output.WriteMessage(StopNotifyingUtxosChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest) { + output.WriteRawTag(218, 66); + output.WriteMessage(NotifyPruningPointUTXOSetOverrideRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse) { + output.WriteRawTag(226, 66); + output.WriteMessage(NotifyPruningPointUTXOSetOverrideResponse); + } + if (payloadCase_ == PayloadOneofCase.PruningPointUTXOSetOverrideNotification) { + output.WriteRawTag(234, 66); + output.WriteMessage(PruningPointUTXOSetOverrideNotification); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest) { + output.WriteRawTag(242, 66); + output.WriteMessage(StopNotifyingPruningPointUTXOSetOverrideRequest); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse) { + output.WriteRawTag(250, 66); + output.WriteMessage(StopNotifyingPruningPointUTXOSetOverrideResponse); + } + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondRequest) { + output.WriteRawTag(130, 67); + output.WriteMessage(EstimateNetworkHashesPerSecondRequest); + } + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondResponse) { + output.WriteRawTag(138, 67); + output.WriteMessage(EstimateNetworkHashesPerSecondResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest) { + output.WriteRawTag(146, 67); + output.WriteMessage(NotifyVirtualDaaScoreChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse) { + output.WriteRawTag(154, 67); + output.WriteMessage(NotifyVirtualDaaScoreChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.VirtualDaaScoreChangedNotification) { + output.WriteRawTag(162, 67); + output.WriteMessage(VirtualDaaScoreChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressRequest) { + output.WriteRawTag(170, 67); + output.WriteMessage(GetBalanceByAddressRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressResponse) { + output.WriteRawTag(178, 67); + output.WriteMessage(GetBalanceByAddressResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesRequest) { + output.WriteRawTag(186, 67); + output.WriteMessage(GetBalancesByAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesResponse) { + output.WriteRawTag(194, 67); + output.WriteMessage(GetBalancesByAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateRequest) { + output.WriteRawTag(202, 67); + output.WriteMessage(NotifyNewBlockTemplateRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateResponse) { + output.WriteRawTag(210, 67); + output.WriteMessage(NotifyNewBlockTemplateResponse); + } + if (payloadCase_ == PayloadOneofCase.NewBlockTemplateNotification) { + output.WriteRawTag(218, 67); + output.WriteMessage(NewBlockTemplateNotification); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesRequest) { + output.WriteRawTag(226, 67); + output.WriteMessage(GetMempoolEntriesByAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesResponse) { + output.WriteRawTag(234, 67); + output.WriteMessage(GetMempoolEntriesByAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyRequest) { + output.WriteRawTag(242, 67); + output.WriteMessage(GetCoinSupplyRequest); + } + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyResponse) { + output.WriteRawTag(250, 67); + output.WriteMessage(GetCoinSupplyResponse); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (payloadCase_ == PayloadOneofCase.Addresses) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Addresses); + } + if (payloadCase_ == PayloadOneofCase.Block) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + if (payloadCase_ == PayloadOneofCase.Transaction) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Transaction); + } + if (payloadCase_ == PayloadOneofCase.BlockLocator) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(BlockLocator); + } + if (payloadCase_ == PayloadOneofCase.RequestAddresses) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(RequestAddresses); + } + if (payloadCase_ == PayloadOneofCase.RequestRelayBlocks) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(RequestRelayBlocks); + } + if (payloadCase_ == PayloadOneofCase.RequestTransactions) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(RequestTransactions); + } + if (payloadCase_ == PayloadOneofCase.IbdBlock) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(IbdBlock); + } + if (payloadCase_ == PayloadOneofCase.InvRelayBlock) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(InvRelayBlock); + } + if (payloadCase_ == PayloadOneofCase.InvTransactions) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(InvTransactions); + } + if (payloadCase_ == PayloadOneofCase.Ping) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Ping); + } + if (payloadCase_ == PayloadOneofCase.Pong) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Pong); + } + if (payloadCase_ == PayloadOneofCase.Verack) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Verack); + } + if (payloadCase_ == PayloadOneofCase.Version) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Version); + } + if (payloadCase_ == PayloadOneofCase.TransactionNotFound) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(TransactionNotFound); + } + if (payloadCase_ == PayloadOneofCase.Reject) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Reject); + } + if (payloadCase_ == PayloadOneofCase.PruningPointUtxoSetChunk) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(PruningPointUtxoSetChunk); + } + if (payloadCase_ == PayloadOneofCase.RequestIBDBlocks) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestIBDBlocks); + } + if (payloadCase_ == PayloadOneofCase.UnexpectedPruningPoint) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(UnexpectedPruningPoint); + } + if (payloadCase_ == PayloadOneofCase.IbdBlockLocator) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(IbdBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHash) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(IbdBlockLocatorHighestHash); + } + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointUtxoSetChunk) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestNextPruningPointUtxoSetChunk); + } + if (payloadCase_ == PayloadOneofCase.DonePruningPointUtxoSetChunks) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(DonePruningPointUtxoSetChunks); + } + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHashNotFound) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(IbdBlockLocatorHighestHashNotFound); + } + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedData) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(BlockWithTrustedData); + } + if (payloadCase_ == PayloadOneofCase.DoneBlocksWithTrustedData) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(DoneBlocksWithTrustedData); + } + if (payloadCase_ == PayloadOneofCase.RequestPruningPointAndItsAnticone) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestPruningPointAndItsAnticone); + } + if (payloadCase_ == PayloadOneofCase.BlockHeaders) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(BlockHeaders); + } + if (payloadCase_ == PayloadOneofCase.RequestNextHeaders) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestNextHeaders); + } + if (payloadCase_ == PayloadOneofCase.DoneHeaders) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(DoneHeaders); + } + if (payloadCase_ == PayloadOneofCase.RequestPruningPointUTXOSet) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestPruningPointUTXOSet); + } + if (payloadCase_ == PayloadOneofCase.RequestHeaders) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestHeaders); + } + if (payloadCase_ == PayloadOneofCase.RequestBlockLocator) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.PruningPoints) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(PruningPoints); + } + if (payloadCase_ == PayloadOneofCase.RequestPruningPointProof) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestPruningPointProof); + } + if (payloadCase_ == PayloadOneofCase.PruningPointProof) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(PruningPointProof); + } + if (payloadCase_ == PayloadOneofCase.Ready) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Ready); + } + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedDataV4) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(BlockWithTrustedDataV4); + } + if (payloadCase_ == PayloadOneofCase.TrustedData) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(TrustedData); + } + if (payloadCase_ == PayloadOneofCase.RequestIBDChainBlockLocator) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestIBDChainBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.IbdChainBlockLocator) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(IbdChainBlockLocator); + } + if (payloadCase_ == PayloadOneofCase.RequestAnticone) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestAnticone); + } + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequestNextPruningPointAndItsAnticoneBlocks); + } + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetCurrentNetworkRequest); + } + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetCurrentNetworkResponse); + } + if (payloadCase_ == PayloadOneofCase.SubmitBlockRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(SubmitBlockRequest); + } + if (payloadCase_ == PayloadOneofCase.SubmitBlockResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(SubmitBlockResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockTemplateRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockTemplateResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyBlockAddedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyBlockAddedResponse); + } + if (payloadCase_ == PayloadOneofCase.BlockAddedNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(BlockAddedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetPeerAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetPeerAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetSelectedTipHashRequest); + } + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetSelectedTipHashResponse); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetMempoolEntryRequest); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetMempoolEntryResponse); + } + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetConnectedPeerInfoRequest); + } + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetConnectedPeerInfoResponse); + } + if (payloadCase_ == PayloadOneofCase.AddPeerRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(AddPeerRequest); + } + if (payloadCase_ == PayloadOneofCase.AddPeerResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(AddPeerResponse); + } + if (payloadCase_ == PayloadOneofCase.SubmitTransactionRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(SubmitTransactionRequest); + } + if (payloadCase_ == PayloadOneofCase.SubmitTransactionResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(SubmitTransactionResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyVirtualSelectedParentChainChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyVirtualSelectedParentChainChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentChainChangedNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(VirtualSelectedParentChainChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetBlockRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockResponse); + } + if (payloadCase_ == PayloadOneofCase.GetSubnetworkRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetSubnetworkRequest); + } + if (payloadCase_ == PayloadOneofCase.GetSubnetworkResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetSubnetworkResponse); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetVirtualSelectedParentChainFromBlockRequest); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetVirtualSelectedParentChainFromBlockResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlocksRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlocksRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlocksResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlocksResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlockCountRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockCountRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockCountResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockCountResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockDagInfoRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBlockDagInfoResponse); + } + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(ResolveFinalityConflictRequest); + } + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(ResolveFinalityConflictResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyFinalityConflictsRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyFinalityConflictsResponse); + } + if (payloadCase_ == PayloadOneofCase.FinalityConflictNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(FinalityConflictNotification); + } + if (payloadCase_ == PayloadOneofCase.FinalityConflictResolvedNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(FinalityConflictResolvedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetMempoolEntriesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetMempoolEntriesResponse); + } + if (payloadCase_ == PayloadOneofCase.ShutDownRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(ShutDownRequest); + } + if (payloadCase_ == PayloadOneofCase.ShutDownResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(ShutDownResponse); + } + if (payloadCase_ == PayloadOneofCase.GetHeadersRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetHeadersRequest); + } + if (payloadCase_ == PayloadOneofCase.GetHeadersResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetHeadersResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyUtxosChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyUtxosChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.UtxosChangedNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(UtxosChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetUtxosByAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetUtxosByAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetVirtualSelectedParentBlueScoreRequest); + } + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetVirtualSelectedParentBlueScoreResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyVirtualSelectedParentBlueScoreChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyVirtualSelectedParentBlueScoreChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(VirtualSelectedParentBlueScoreChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.BanRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(BanRequest); + } + if (payloadCase_ == PayloadOneofCase.BanResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(BanResponse); + } + if (payloadCase_ == PayloadOneofCase.UnbanRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(UnbanRequest); + } + if (payloadCase_ == PayloadOneofCase.UnbanResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(UnbanResponse); + } + if (payloadCase_ == PayloadOneofCase.GetInfoRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetInfoRequest); + } + if (payloadCase_ == PayloadOneofCase.GetInfoResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetInfoResponse); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(StopNotifyingUtxosChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(StopNotifyingUtxosChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyPruningPointUTXOSetOverrideRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyPruningPointUTXOSetOverrideResponse); + } + if (payloadCase_ == PayloadOneofCase.PruningPointUTXOSetOverrideNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(PruningPointUTXOSetOverrideNotification); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(StopNotifyingPruningPointUTXOSetOverrideRequest); + } + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(StopNotifyingPruningPointUTXOSetOverrideResponse); + } + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(EstimateNetworkHashesPerSecondRequest); + } + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(EstimateNetworkHashesPerSecondResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyVirtualDaaScoreChangedRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyVirtualDaaScoreChangedResponse); + } + if (payloadCase_ == PayloadOneofCase.VirtualDaaScoreChangedNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(VirtualDaaScoreChangedNotification); + } + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBalanceByAddressRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBalanceByAddressResponse); + } + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBalancesByAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetBalancesByAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyNewBlockTemplateRequest); + } + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NotifyNewBlockTemplateResponse); + } + if (payloadCase_ == PayloadOneofCase.NewBlockTemplateNotification) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(NewBlockTemplateNotification); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetMempoolEntriesByAddressesRequest); + } + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetMempoolEntriesByAddressesResponse); + } + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyRequest) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetCoinSupplyRequest); + } + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyResponse) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(GetCoinSupplyResponse); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(KaspadMessage other) { + if (other == null) { + return; + } + switch (other.PayloadCase) { + case PayloadOneofCase.Addresses: + if (Addresses == null) { + Addresses = new global::Miningcore.Blockchain.Kaspa.Kaspad.AddressesMessage(); + } + Addresses.MergeFrom(other.Addresses); + break; + case PayloadOneofCase.Block: + if (Block == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + Block.MergeFrom(other.Block); + break; + case PayloadOneofCase.Transaction: + if (Transaction == null) { + Transaction = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage(); + } + Transaction.MergeFrom(other.Transaction); + break; + case PayloadOneofCase.BlockLocator: + if (BlockLocator == null) { + BlockLocator = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLocatorMessage(); + } + BlockLocator.MergeFrom(other.BlockLocator); + break; + case PayloadOneofCase.RequestAddresses: + if (RequestAddresses == null) { + RequestAddresses = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAddressesMessage(); + } + RequestAddresses.MergeFrom(other.RequestAddresses); + break; + case PayloadOneofCase.RequestRelayBlocks: + if (RequestRelayBlocks == null) { + RequestRelayBlocks = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestRelayBlocksMessage(); + } + RequestRelayBlocks.MergeFrom(other.RequestRelayBlocks); + break; + case PayloadOneofCase.RequestTransactions: + if (RequestTransactions == null) { + RequestTransactions = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestTransactionsMessage(); + } + RequestTransactions.MergeFrom(other.RequestTransactions); + break; + case PayloadOneofCase.IbdBlock: + if (IbdBlock == null) { + IbdBlock = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + IbdBlock.MergeFrom(other.IbdBlock); + break; + case PayloadOneofCase.InvRelayBlock: + if (InvRelayBlock == null) { + InvRelayBlock = new global::Miningcore.Blockchain.Kaspa.Kaspad.InvRelayBlockMessage(); + } + InvRelayBlock.MergeFrom(other.InvRelayBlock); + break; + case PayloadOneofCase.InvTransactions: + if (InvTransactions == null) { + InvTransactions = new global::Miningcore.Blockchain.Kaspa.Kaspad.InvTransactionsMessage(); + } + InvTransactions.MergeFrom(other.InvTransactions); + break; + case PayloadOneofCase.Ping: + if (Ping == null) { + Ping = new global::Miningcore.Blockchain.Kaspa.Kaspad.PingMessage(); + } + Ping.MergeFrom(other.Ping); + break; + case PayloadOneofCase.Pong: + if (Pong == null) { + Pong = new global::Miningcore.Blockchain.Kaspa.Kaspad.PongMessage(); + } + Pong.MergeFrom(other.Pong); + break; + case PayloadOneofCase.Verack: + if (Verack == null) { + Verack = new global::Miningcore.Blockchain.Kaspa.Kaspad.VerackMessage(); + } + Verack.MergeFrom(other.Verack); + break; + case PayloadOneofCase.Version: + if (Version == null) { + Version = new global::Miningcore.Blockchain.Kaspa.Kaspad.VersionMessage(); + } + Version.MergeFrom(other.Version); + break; + case PayloadOneofCase.TransactionNotFound: + if (TransactionNotFound == null) { + TransactionNotFound = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionNotFoundMessage(); + } + TransactionNotFound.MergeFrom(other.TransactionNotFound); + break; + case PayloadOneofCase.Reject: + if (Reject == null) { + Reject = new global::Miningcore.Blockchain.Kaspa.Kaspad.RejectMessage(); + } + Reject.MergeFrom(other.Reject); + break; + case PayloadOneofCase.PruningPointUtxoSetChunk: + if (PruningPointUtxoSetChunk == null) { + PruningPointUtxoSetChunk = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUtxoSetChunkMessage(); + } + PruningPointUtxoSetChunk.MergeFrom(other.PruningPointUtxoSetChunk); + break; + case PayloadOneofCase.RequestIBDBlocks: + if (RequestIBDBlocks == null) { + RequestIBDBlocks = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDBlocksMessage(); + } + RequestIBDBlocks.MergeFrom(other.RequestIBDBlocks); + break; + case PayloadOneofCase.UnexpectedPruningPoint: + if (UnexpectedPruningPoint == null) { + UnexpectedPruningPoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.UnexpectedPruningPointMessage(); + } + UnexpectedPruningPoint.MergeFrom(other.UnexpectedPruningPoint); + break; + case PayloadOneofCase.IbdBlockLocator: + if (IbdBlockLocator == null) { + IbdBlockLocator = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorMessage(); + } + IbdBlockLocator.MergeFrom(other.IbdBlockLocator); + break; + case PayloadOneofCase.IbdBlockLocatorHighestHash: + if (IbdBlockLocatorHighestHash == null) { + IbdBlockLocatorHighestHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashMessage(); + } + IbdBlockLocatorHighestHash.MergeFrom(other.IbdBlockLocatorHighestHash); + break; + case PayloadOneofCase.RequestNextPruningPointUtxoSetChunk: + if (RequestNextPruningPointUtxoSetChunk == null) { + RequestNextPruningPointUtxoSetChunk = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointUtxoSetChunkMessage(); + } + RequestNextPruningPointUtxoSetChunk.MergeFrom(other.RequestNextPruningPointUtxoSetChunk); + break; + case PayloadOneofCase.DonePruningPointUtxoSetChunks: + if (DonePruningPointUtxoSetChunks == null) { + DonePruningPointUtxoSetChunks = new global::Miningcore.Blockchain.Kaspa.Kaspad.DonePruningPointUtxoSetChunksMessage(); + } + DonePruningPointUtxoSetChunks.MergeFrom(other.DonePruningPointUtxoSetChunks); + break; + case PayloadOneofCase.IbdBlockLocatorHighestHashNotFound: + if (IbdBlockLocatorHighestHashNotFound == null) { + IbdBlockLocatorHighestHashNotFound = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashNotFoundMessage(); + } + IbdBlockLocatorHighestHashNotFound.MergeFrom(other.IbdBlockLocatorHighestHashNotFound); + break; + case PayloadOneofCase.BlockWithTrustedData: + if (BlockWithTrustedData == null) { + BlockWithTrustedData = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataMessage(); + } + BlockWithTrustedData.MergeFrom(other.BlockWithTrustedData); + break; + case PayloadOneofCase.DoneBlocksWithTrustedData: + if (DoneBlocksWithTrustedData == null) { + DoneBlocksWithTrustedData = new global::Miningcore.Blockchain.Kaspa.Kaspad.DoneBlocksWithTrustedDataMessage(); + } + DoneBlocksWithTrustedData.MergeFrom(other.DoneBlocksWithTrustedData); + break; + case PayloadOneofCase.RequestPruningPointAndItsAnticone: + if (RequestPruningPointAndItsAnticone == null) { + RequestPruningPointAndItsAnticone = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointAndItsAnticoneMessage(); + } + RequestPruningPointAndItsAnticone.MergeFrom(other.RequestPruningPointAndItsAnticone); + break; + case PayloadOneofCase.BlockHeaders: + if (BlockHeaders == null) { + BlockHeaders = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeadersMessage(); + } + BlockHeaders.MergeFrom(other.BlockHeaders); + break; + case PayloadOneofCase.RequestNextHeaders: + if (RequestNextHeaders == null) { + RequestNextHeaders = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextHeadersMessage(); + } + RequestNextHeaders.MergeFrom(other.RequestNextHeaders); + break; + case PayloadOneofCase.DoneHeaders: + if (DoneHeaders == null) { + DoneHeaders = new global::Miningcore.Blockchain.Kaspa.Kaspad.DoneHeadersMessage(); + } + DoneHeaders.MergeFrom(other.DoneHeaders); + break; + case PayloadOneofCase.RequestPruningPointUTXOSet: + if (RequestPruningPointUTXOSet == null) { + RequestPruningPointUTXOSet = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointUTXOSetMessage(); + } + RequestPruningPointUTXOSet.MergeFrom(other.RequestPruningPointUTXOSet); + break; + case PayloadOneofCase.RequestHeaders: + if (RequestHeaders == null) { + RequestHeaders = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestHeadersMessage(); + } + RequestHeaders.MergeFrom(other.RequestHeaders); + break; + case PayloadOneofCase.RequestBlockLocator: + if (RequestBlockLocator == null) { + RequestBlockLocator = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestBlockLocatorMessage(); + } + RequestBlockLocator.MergeFrom(other.RequestBlockLocator); + break; + case PayloadOneofCase.PruningPoints: + if (PruningPoints == null) { + PruningPoints = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointsMessage(); + } + PruningPoints.MergeFrom(other.PruningPoints); + break; + case PayloadOneofCase.RequestPruningPointProof: + if (RequestPruningPointProof == null) { + RequestPruningPointProof = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointProofMessage(); + } + RequestPruningPointProof.MergeFrom(other.RequestPruningPointProof); + break; + case PayloadOneofCase.PruningPointProof: + if (PruningPointProof == null) { + PruningPointProof = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofMessage(); + } + PruningPointProof.MergeFrom(other.PruningPointProof); + break; + case PayloadOneofCase.Ready: + if (Ready == null) { + Ready = new global::Miningcore.Blockchain.Kaspa.Kaspad.ReadyMessage(); + } + Ready.MergeFrom(other.Ready); + break; + case PayloadOneofCase.BlockWithTrustedDataV4: + if (BlockWithTrustedDataV4 == null) { + BlockWithTrustedDataV4 = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataV4Message(); + } + BlockWithTrustedDataV4.MergeFrom(other.BlockWithTrustedDataV4); + break; + case PayloadOneofCase.TrustedData: + if (TrustedData == null) { + TrustedData = new global::Miningcore.Blockchain.Kaspa.Kaspad.TrustedDataMessage(); + } + TrustedData.MergeFrom(other.TrustedData); + break; + case PayloadOneofCase.RequestIBDChainBlockLocator: + if (RequestIBDChainBlockLocator == null) { + RequestIBDChainBlockLocator = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDChainBlockLocatorMessage(); + } + RequestIBDChainBlockLocator.MergeFrom(other.RequestIBDChainBlockLocator); + break; + case PayloadOneofCase.IbdChainBlockLocator: + if (IbdChainBlockLocator == null) { + IbdChainBlockLocator = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdChainBlockLocatorMessage(); + } + IbdChainBlockLocator.MergeFrom(other.IbdChainBlockLocator); + break; + case PayloadOneofCase.RequestAnticone: + if (RequestAnticone == null) { + RequestAnticone = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAnticoneMessage(); + } + RequestAnticone.MergeFrom(other.RequestAnticone); + break; + case PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks: + if (RequestNextPruningPointAndItsAnticoneBlocks == null) { + RequestNextPruningPointAndItsAnticoneBlocks = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointAndItsAnticoneBlocksMessage(); + } + RequestNextPruningPointAndItsAnticoneBlocks.MergeFrom(other.RequestNextPruningPointAndItsAnticoneBlocks); + break; + case PayloadOneofCase.GetCurrentNetworkRequest: + if (GetCurrentNetworkRequest == null) { + GetCurrentNetworkRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkRequestMessage(); + } + GetCurrentNetworkRequest.MergeFrom(other.GetCurrentNetworkRequest); + break; + case PayloadOneofCase.GetCurrentNetworkResponse: + if (GetCurrentNetworkResponse == null) { + GetCurrentNetworkResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkResponseMessage(); + } + GetCurrentNetworkResponse.MergeFrom(other.GetCurrentNetworkResponse); + break; + case PayloadOneofCase.SubmitBlockRequest: + if (SubmitBlockRequest == null) { + SubmitBlockRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockRequestMessage(); + } + SubmitBlockRequest.MergeFrom(other.SubmitBlockRequest); + break; + case PayloadOneofCase.SubmitBlockResponse: + if (SubmitBlockResponse == null) { + SubmitBlockResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage(); + } + SubmitBlockResponse.MergeFrom(other.SubmitBlockResponse); + break; + case PayloadOneofCase.GetBlockTemplateRequest: + if (GetBlockTemplateRequest == null) { + GetBlockTemplateRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateRequestMessage(); + } + GetBlockTemplateRequest.MergeFrom(other.GetBlockTemplateRequest); + break; + case PayloadOneofCase.GetBlockTemplateResponse: + if (GetBlockTemplateResponse == null) { + GetBlockTemplateResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateResponseMessage(); + } + GetBlockTemplateResponse.MergeFrom(other.GetBlockTemplateResponse); + break; + case PayloadOneofCase.NotifyBlockAddedRequest: + if (NotifyBlockAddedRequest == null) { + NotifyBlockAddedRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedRequestMessage(); + } + NotifyBlockAddedRequest.MergeFrom(other.NotifyBlockAddedRequest); + break; + case PayloadOneofCase.NotifyBlockAddedResponse: + if (NotifyBlockAddedResponse == null) { + NotifyBlockAddedResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedResponseMessage(); + } + NotifyBlockAddedResponse.MergeFrom(other.NotifyBlockAddedResponse); + break; + case PayloadOneofCase.BlockAddedNotification: + if (BlockAddedNotification == null) { + BlockAddedNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockAddedNotificationMessage(); + } + BlockAddedNotification.MergeFrom(other.BlockAddedNotification); + break; + case PayloadOneofCase.GetPeerAddressesRequest: + if (GetPeerAddressesRequest == null) { + GetPeerAddressesRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesRequestMessage(); + } + GetPeerAddressesRequest.MergeFrom(other.GetPeerAddressesRequest); + break; + case PayloadOneofCase.GetPeerAddressesResponse: + if (GetPeerAddressesResponse == null) { + GetPeerAddressesResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesResponseMessage(); + } + GetPeerAddressesResponse.MergeFrom(other.GetPeerAddressesResponse); + break; + case PayloadOneofCase.GetSelectedTipHashRequest: + if (GetSelectedTipHashRequest == null) { + GetSelectedTipHashRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashRequestMessage(); + } + GetSelectedTipHashRequest.MergeFrom(other.GetSelectedTipHashRequest); + break; + case PayloadOneofCase.GetSelectedTipHashResponse: + if (GetSelectedTipHashResponse == null) { + GetSelectedTipHashResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashResponseMessage(); + } + GetSelectedTipHashResponse.MergeFrom(other.GetSelectedTipHashResponse); + break; + case PayloadOneofCase.GetMempoolEntryRequest: + if (GetMempoolEntryRequest == null) { + GetMempoolEntryRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryRequestMessage(); + } + GetMempoolEntryRequest.MergeFrom(other.GetMempoolEntryRequest); + break; + case PayloadOneofCase.GetMempoolEntryResponse: + if (GetMempoolEntryResponse == null) { + GetMempoolEntryResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryResponseMessage(); + } + GetMempoolEntryResponse.MergeFrom(other.GetMempoolEntryResponse); + break; + case PayloadOneofCase.GetConnectedPeerInfoRequest: + if (GetConnectedPeerInfoRequest == null) { + GetConnectedPeerInfoRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoRequestMessage(); + } + GetConnectedPeerInfoRequest.MergeFrom(other.GetConnectedPeerInfoRequest); + break; + case PayloadOneofCase.GetConnectedPeerInfoResponse: + if (GetConnectedPeerInfoResponse == null) { + GetConnectedPeerInfoResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoResponseMessage(); + } + GetConnectedPeerInfoResponse.MergeFrom(other.GetConnectedPeerInfoResponse); + break; + case PayloadOneofCase.AddPeerRequest: + if (AddPeerRequest == null) { + AddPeerRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerRequestMessage(); + } + AddPeerRequest.MergeFrom(other.AddPeerRequest); + break; + case PayloadOneofCase.AddPeerResponse: + if (AddPeerResponse == null) { + AddPeerResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerResponseMessage(); + } + AddPeerResponse.MergeFrom(other.AddPeerResponse); + break; + case PayloadOneofCase.SubmitTransactionRequest: + if (SubmitTransactionRequest == null) { + SubmitTransactionRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionRequestMessage(); + } + SubmitTransactionRequest.MergeFrom(other.SubmitTransactionRequest); + break; + case PayloadOneofCase.SubmitTransactionResponse: + if (SubmitTransactionResponse == null) { + SubmitTransactionResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionResponseMessage(); + } + SubmitTransactionResponse.MergeFrom(other.SubmitTransactionResponse); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest: + if (NotifyVirtualSelectedParentChainChangedRequest == null) { + NotifyVirtualSelectedParentChainChangedRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedRequestMessage(); + } + NotifyVirtualSelectedParentChainChangedRequest.MergeFrom(other.NotifyVirtualSelectedParentChainChangedRequest); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse: + if (NotifyVirtualSelectedParentChainChangedResponse == null) { + NotifyVirtualSelectedParentChainChangedResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedResponseMessage(); + } + NotifyVirtualSelectedParentChainChangedResponse.MergeFrom(other.NotifyVirtualSelectedParentChainChangedResponse); + break; + case PayloadOneofCase.VirtualSelectedParentChainChangedNotification: + if (VirtualSelectedParentChainChangedNotification == null) { + VirtualSelectedParentChainChangedNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentChainChangedNotificationMessage(); + } + VirtualSelectedParentChainChangedNotification.MergeFrom(other.VirtualSelectedParentChainChangedNotification); + break; + case PayloadOneofCase.GetBlockRequest: + if (GetBlockRequest == null) { + GetBlockRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockRequestMessage(); + } + GetBlockRequest.MergeFrom(other.GetBlockRequest); + break; + case PayloadOneofCase.GetBlockResponse: + if (GetBlockResponse == null) { + GetBlockResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockResponseMessage(); + } + GetBlockResponse.MergeFrom(other.GetBlockResponse); + break; + case PayloadOneofCase.GetSubnetworkRequest: + if (GetSubnetworkRequest == null) { + GetSubnetworkRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkRequestMessage(); + } + GetSubnetworkRequest.MergeFrom(other.GetSubnetworkRequest); + break; + case PayloadOneofCase.GetSubnetworkResponse: + if (GetSubnetworkResponse == null) { + GetSubnetworkResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkResponseMessage(); + } + GetSubnetworkResponse.MergeFrom(other.GetSubnetworkResponse); + break; + case PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest: + if (GetVirtualSelectedParentChainFromBlockRequest == null) { + GetVirtualSelectedParentChainFromBlockRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockRequestMessage(); + } + GetVirtualSelectedParentChainFromBlockRequest.MergeFrom(other.GetVirtualSelectedParentChainFromBlockRequest); + break; + case PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse: + if (GetVirtualSelectedParentChainFromBlockResponse == null) { + GetVirtualSelectedParentChainFromBlockResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockResponseMessage(); + } + GetVirtualSelectedParentChainFromBlockResponse.MergeFrom(other.GetVirtualSelectedParentChainFromBlockResponse); + break; + case PayloadOneofCase.GetBlocksRequest: + if (GetBlocksRequest == null) { + GetBlocksRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksRequestMessage(); + } + GetBlocksRequest.MergeFrom(other.GetBlocksRequest); + break; + case PayloadOneofCase.GetBlocksResponse: + if (GetBlocksResponse == null) { + GetBlocksResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksResponseMessage(); + } + GetBlocksResponse.MergeFrom(other.GetBlocksResponse); + break; + case PayloadOneofCase.GetBlockCountRequest: + if (GetBlockCountRequest == null) { + GetBlockCountRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountRequestMessage(); + } + GetBlockCountRequest.MergeFrom(other.GetBlockCountRequest); + break; + case PayloadOneofCase.GetBlockCountResponse: + if (GetBlockCountResponse == null) { + GetBlockCountResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountResponseMessage(); + } + GetBlockCountResponse.MergeFrom(other.GetBlockCountResponse); + break; + case PayloadOneofCase.GetBlockDagInfoRequest: + if (GetBlockDagInfoRequest == null) { + GetBlockDagInfoRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoRequestMessage(); + } + GetBlockDagInfoRequest.MergeFrom(other.GetBlockDagInfoRequest); + break; + case PayloadOneofCase.GetBlockDagInfoResponse: + if (GetBlockDagInfoResponse == null) { + GetBlockDagInfoResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoResponseMessage(); + } + GetBlockDagInfoResponse.MergeFrom(other.GetBlockDagInfoResponse); + break; + case PayloadOneofCase.ResolveFinalityConflictRequest: + if (ResolveFinalityConflictRequest == null) { + ResolveFinalityConflictRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictRequestMessage(); + } + ResolveFinalityConflictRequest.MergeFrom(other.ResolveFinalityConflictRequest); + break; + case PayloadOneofCase.ResolveFinalityConflictResponse: + if (ResolveFinalityConflictResponse == null) { + ResolveFinalityConflictResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictResponseMessage(); + } + ResolveFinalityConflictResponse.MergeFrom(other.ResolveFinalityConflictResponse); + break; + case PayloadOneofCase.NotifyFinalityConflictsRequest: + if (NotifyFinalityConflictsRequest == null) { + NotifyFinalityConflictsRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsRequestMessage(); + } + NotifyFinalityConflictsRequest.MergeFrom(other.NotifyFinalityConflictsRequest); + break; + case PayloadOneofCase.NotifyFinalityConflictsResponse: + if (NotifyFinalityConflictsResponse == null) { + NotifyFinalityConflictsResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsResponseMessage(); + } + NotifyFinalityConflictsResponse.MergeFrom(other.NotifyFinalityConflictsResponse); + break; + case PayloadOneofCase.FinalityConflictNotification: + if (FinalityConflictNotification == null) { + FinalityConflictNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictNotificationMessage(); + } + FinalityConflictNotification.MergeFrom(other.FinalityConflictNotification); + break; + case PayloadOneofCase.FinalityConflictResolvedNotification: + if (FinalityConflictResolvedNotification == null) { + FinalityConflictResolvedNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictResolvedNotificationMessage(); + } + FinalityConflictResolvedNotification.MergeFrom(other.FinalityConflictResolvedNotification); + break; + case PayloadOneofCase.GetMempoolEntriesRequest: + if (GetMempoolEntriesRequest == null) { + GetMempoolEntriesRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesRequestMessage(); + } + GetMempoolEntriesRequest.MergeFrom(other.GetMempoolEntriesRequest); + break; + case PayloadOneofCase.GetMempoolEntriesResponse: + if (GetMempoolEntriesResponse == null) { + GetMempoolEntriesResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesResponseMessage(); + } + GetMempoolEntriesResponse.MergeFrom(other.GetMempoolEntriesResponse); + break; + case PayloadOneofCase.ShutDownRequest: + if (ShutDownRequest == null) { + ShutDownRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownRequestMessage(); + } + ShutDownRequest.MergeFrom(other.ShutDownRequest); + break; + case PayloadOneofCase.ShutDownResponse: + if (ShutDownResponse == null) { + ShutDownResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownResponseMessage(); + } + ShutDownResponse.MergeFrom(other.ShutDownResponse); + break; + case PayloadOneofCase.GetHeadersRequest: + if (GetHeadersRequest == null) { + GetHeadersRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersRequestMessage(); + } + GetHeadersRequest.MergeFrom(other.GetHeadersRequest); + break; + case PayloadOneofCase.GetHeadersResponse: + if (GetHeadersResponse == null) { + GetHeadersResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersResponseMessage(); + } + GetHeadersResponse.MergeFrom(other.GetHeadersResponse); + break; + case PayloadOneofCase.NotifyUtxosChangedRequest: + if (NotifyUtxosChangedRequest == null) { + NotifyUtxosChangedRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedRequestMessage(); + } + NotifyUtxosChangedRequest.MergeFrom(other.NotifyUtxosChangedRequest); + break; + case PayloadOneofCase.NotifyUtxosChangedResponse: + if (NotifyUtxosChangedResponse == null) { + NotifyUtxosChangedResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedResponseMessage(); + } + NotifyUtxosChangedResponse.MergeFrom(other.NotifyUtxosChangedResponse); + break; + case PayloadOneofCase.UtxosChangedNotification: + if (UtxosChangedNotification == null) { + UtxosChangedNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosChangedNotificationMessage(); + } + UtxosChangedNotification.MergeFrom(other.UtxosChangedNotification); + break; + case PayloadOneofCase.GetUtxosByAddressesRequest: + if (GetUtxosByAddressesRequest == null) { + GetUtxosByAddressesRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesRequestMessage(); + } + GetUtxosByAddressesRequest.MergeFrom(other.GetUtxosByAddressesRequest); + break; + case PayloadOneofCase.GetUtxosByAddressesResponse: + if (GetUtxosByAddressesResponse == null) { + GetUtxosByAddressesResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesResponseMessage(); + } + GetUtxosByAddressesResponse.MergeFrom(other.GetUtxosByAddressesResponse); + break; + case PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest: + if (GetVirtualSelectedParentBlueScoreRequest == null) { + GetVirtualSelectedParentBlueScoreRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreRequestMessage(); + } + GetVirtualSelectedParentBlueScoreRequest.MergeFrom(other.GetVirtualSelectedParentBlueScoreRequest); + break; + case PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse: + if (GetVirtualSelectedParentBlueScoreResponse == null) { + GetVirtualSelectedParentBlueScoreResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreResponseMessage(); + } + GetVirtualSelectedParentBlueScoreResponse.MergeFrom(other.GetVirtualSelectedParentBlueScoreResponse); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest: + if (NotifyVirtualSelectedParentBlueScoreChangedRequest == null) { + NotifyVirtualSelectedParentBlueScoreChangedRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage(); + } + NotifyVirtualSelectedParentBlueScoreChangedRequest.MergeFrom(other.NotifyVirtualSelectedParentBlueScoreChangedRequest); + break; + case PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse: + if (NotifyVirtualSelectedParentBlueScoreChangedResponse == null) { + NotifyVirtualSelectedParentBlueScoreChangedResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage(); + } + NotifyVirtualSelectedParentBlueScoreChangedResponse.MergeFrom(other.NotifyVirtualSelectedParentBlueScoreChangedResponse); + break; + case PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification: + if (VirtualSelectedParentBlueScoreChangedNotification == null) { + VirtualSelectedParentBlueScoreChangedNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentBlueScoreChangedNotificationMessage(); + } + VirtualSelectedParentBlueScoreChangedNotification.MergeFrom(other.VirtualSelectedParentBlueScoreChangedNotification); + break; + case PayloadOneofCase.BanRequest: + if (BanRequest == null) { + BanRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.BanRequestMessage(); + } + BanRequest.MergeFrom(other.BanRequest); + break; + case PayloadOneofCase.BanResponse: + if (BanResponse == null) { + BanResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.BanResponseMessage(); + } + BanResponse.MergeFrom(other.BanResponse); + break; + case PayloadOneofCase.UnbanRequest: + if (UnbanRequest == null) { + UnbanRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanRequestMessage(); + } + UnbanRequest.MergeFrom(other.UnbanRequest); + break; + case PayloadOneofCase.UnbanResponse: + if (UnbanResponse == null) { + UnbanResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanResponseMessage(); + } + UnbanResponse.MergeFrom(other.UnbanResponse); + break; + case PayloadOneofCase.GetInfoRequest: + if (GetInfoRequest == null) { + GetInfoRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoRequestMessage(); + } + GetInfoRequest.MergeFrom(other.GetInfoRequest); + break; + case PayloadOneofCase.GetInfoResponse: + if (GetInfoResponse == null) { + GetInfoResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoResponseMessage(); + } + GetInfoResponse.MergeFrom(other.GetInfoResponse); + break; + case PayloadOneofCase.StopNotifyingUtxosChangedRequest: + if (StopNotifyingUtxosChangedRequest == null) { + StopNotifyingUtxosChangedRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedRequestMessage(); + } + StopNotifyingUtxosChangedRequest.MergeFrom(other.StopNotifyingUtxosChangedRequest); + break; + case PayloadOneofCase.StopNotifyingUtxosChangedResponse: + if (StopNotifyingUtxosChangedResponse == null) { + StopNotifyingUtxosChangedResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedResponseMessage(); + } + StopNotifyingUtxosChangedResponse.MergeFrom(other.StopNotifyingUtxosChangedResponse); + break; + case PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest: + if (NotifyPruningPointUTXOSetOverrideRequest == null) { + NotifyPruningPointUTXOSetOverrideRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideRequestMessage(); + } + NotifyPruningPointUTXOSetOverrideRequest.MergeFrom(other.NotifyPruningPointUTXOSetOverrideRequest); + break; + case PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse: + if (NotifyPruningPointUTXOSetOverrideResponse == null) { + NotifyPruningPointUTXOSetOverrideResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideResponseMessage(); + } + NotifyPruningPointUTXOSetOverrideResponse.MergeFrom(other.NotifyPruningPointUTXOSetOverrideResponse); + break; + case PayloadOneofCase.PruningPointUTXOSetOverrideNotification: + if (PruningPointUTXOSetOverrideNotification == null) { + PruningPointUTXOSetOverrideNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUTXOSetOverrideNotificationMessage(); + } + PruningPointUTXOSetOverrideNotification.MergeFrom(other.PruningPointUTXOSetOverrideNotification); + break; + case PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest: + if (StopNotifyingPruningPointUTXOSetOverrideRequest == null) { + StopNotifyingPruningPointUTXOSetOverrideRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideRequestMessage(); + } + StopNotifyingPruningPointUTXOSetOverrideRequest.MergeFrom(other.StopNotifyingPruningPointUTXOSetOverrideRequest); + break; + case PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse: + if (StopNotifyingPruningPointUTXOSetOverrideResponse == null) { + StopNotifyingPruningPointUTXOSetOverrideResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideResponseMessage(); + } + StopNotifyingPruningPointUTXOSetOverrideResponse.MergeFrom(other.StopNotifyingPruningPointUTXOSetOverrideResponse); + break; + case PayloadOneofCase.EstimateNetworkHashesPerSecondRequest: + if (EstimateNetworkHashesPerSecondRequest == null) { + EstimateNetworkHashesPerSecondRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondRequestMessage(); + } + EstimateNetworkHashesPerSecondRequest.MergeFrom(other.EstimateNetworkHashesPerSecondRequest); + break; + case PayloadOneofCase.EstimateNetworkHashesPerSecondResponse: + if (EstimateNetworkHashesPerSecondResponse == null) { + EstimateNetworkHashesPerSecondResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondResponseMessage(); + } + EstimateNetworkHashesPerSecondResponse.MergeFrom(other.EstimateNetworkHashesPerSecondResponse); + break; + case PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest: + if (NotifyVirtualDaaScoreChangedRequest == null) { + NotifyVirtualDaaScoreChangedRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedRequestMessage(); + } + NotifyVirtualDaaScoreChangedRequest.MergeFrom(other.NotifyVirtualDaaScoreChangedRequest); + break; + case PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse: + if (NotifyVirtualDaaScoreChangedResponse == null) { + NotifyVirtualDaaScoreChangedResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedResponseMessage(); + } + NotifyVirtualDaaScoreChangedResponse.MergeFrom(other.NotifyVirtualDaaScoreChangedResponse); + break; + case PayloadOneofCase.VirtualDaaScoreChangedNotification: + if (VirtualDaaScoreChangedNotification == null) { + VirtualDaaScoreChangedNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualDaaScoreChangedNotificationMessage(); + } + VirtualDaaScoreChangedNotification.MergeFrom(other.VirtualDaaScoreChangedNotification); + break; + case PayloadOneofCase.GetBalanceByAddressRequest: + if (GetBalanceByAddressRequest == null) { + GetBalanceByAddressRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressRequestMessage(); + } + GetBalanceByAddressRequest.MergeFrom(other.GetBalanceByAddressRequest); + break; + case PayloadOneofCase.GetBalanceByAddressResponse: + if (GetBalanceByAddressResponse == null) { + GetBalanceByAddressResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressResponseMessage(); + } + GetBalanceByAddressResponse.MergeFrom(other.GetBalanceByAddressResponse); + break; + case PayloadOneofCase.GetBalancesByAddressesRequest: + if (GetBalancesByAddressesRequest == null) { + GetBalancesByAddressesRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesRequestMessage(); + } + GetBalancesByAddressesRequest.MergeFrom(other.GetBalancesByAddressesRequest); + break; + case PayloadOneofCase.GetBalancesByAddressesResponse: + if (GetBalancesByAddressesResponse == null) { + GetBalancesByAddressesResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesResponseMessage(); + } + GetBalancesByAddressesResponse.MergeFrom(other.GetBalancesByAddressesResponse); + break; + case PayloadOneofCase.NotifyNewBlockTemplateRequest: + if (NotifyNewBlockTemplateRequest == null) { + NotifyNewBlockTemplateRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateRequestMessage(); + } + NotifyNewBlockTemplateRequest.MergeFrom(other.NotifyNewBlockTemplateRequest); + break; + case PayloadOneofCase.NotifyNewBlockTemplateResponse: + if (NotifyNewBlockTemplateResponse == null) { + NotifyNewBlockTemplateResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateResponseMessage(); + } + NotifyNewBlockTemplateResponse.MergeFrom(other.NotifyNewBlockTemplateResponse); + break; + case PayloadOneofCase.NewBlockTemplateNotification: + if (NewBlockTemplateNotification == null) { + NewBlockTemplateNotification = new global::Miningcore.Blockchain.Kaspa.Kaspad.NewBlockTemplateNotificationMessage(); + } + NewBlockTemplateNotification.MergeFrom(other.NewBlockTemplateNotification); + break; + case PayloadOneofCase.GetMempoolEntriesByAddressesRequest: + if (GetMempoolEntriesByAddressesRequest == null) { + GetMempoolEntriesByAddressesRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesRequestMessage(); + } + GetMempoolEntriesByAddressesRequest.MergeFrom(other.GetMempoolEntriesByAddressesRequest); + break; + case PayloadOneofCase.GetMempoolEntriesByAddressesResponse: + if (GetMempoolEntriesByAddressesResponse == null) { + GetMempoolEntriesByAddressesResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesResponseMessage(); + } + GetMempoolEntriesByAddressesResponse.MergeFrom(other.GetMempoolEntriesByAddressesResponse); + break; + case PayloadOneofCase.GetCoinSupplyRequest: + if (GetCoinSupplyRequest == null) { + GetCoinSupplyRequest = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyRequestMessage(); + } + GetCoinSupplyRequest.MergeFrom(other.GetCoinSupplyRequest); + break; + case PayloadOneofCase.GetCoinSupplyResponse: + if (GetCoinSupplyResponse == null) { + GetCoinSupplyResponse = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyResponseMessage(); + } + GetCoinSupplyResponse.MergeFrom(other.GetCoinSupplyResponse); + 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 10: { + global::Miningcore.Blockchain.Kaspa.Kaspad.AddressesMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.AddressesMessage(); + if (payloadCase_ == PayloadOneofCase.Addresses) { + subBuilder.MergeFrom(Addresses); + } + input.ReadMessage(subBuilder); + Addresses = subBuilder; + break; + } + case 18: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + if (payloadCase_ == PayloadOneofCase.Block) { + subBuilder.MergeFrom(Block); + } + input.ReadMessage(subBuilder); + Block = subBuilder; + break; + } + case 26: { + global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage(); + if (payloadCase_ == PayloadOneofCase.Transaction) { + subBuilder.MergeFrom(Transaction); + } + input.ReadMessage(subBuilder); + Transaction = subBuilder; + break; + } + case 42: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLocatorMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLocatorMessage(); + if (payloadCase_ == PayloadOneofCase.BlockLocator) { + subBuilder.MergeFrom(BlockLocator); + } + input.ReadMessage(subBuilder); + BlockLocator = subBuilder; + break; + } + case 50: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAddressesMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAddressesMessage(); + if (payloadCase_ == PayloadOneofCase.RequestAddresses) { + subBuilder.MergeFrom(RequestAddresses); + } + input.ReadMessage(subBuilder); + RequestAddresses = subBuilder; + break; + } + case 82: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestRelayBlocksMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestRelayBlocksMessage(); + if (payloadCase_ == PayloadOneofCase.RequestRelayBlocks) { + subBuilder.MergeFrom(RequestRelayBlocks); + } + input.ReadMessage(subBuilder); + RequestRelayBlocks = subBuilder; + break; + } + case 98: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestTransactionsMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestTransactionsMessage(); + if (payloadCase_ == PayloadOneofCase.RequestTransactions) { + subBuilder.MergeFrom(RequestTransactions); + } + input.ReadMessage(subBuilder); + RequestTransactions = subBuilder; + break; + } + case 106: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + if (payloadCase_ == PayloadOneofCase.IbdBlock) { + subBuilder.MergeFrom(IbdBlock); + } + input.ReadMessage(subBuilder); + IbdBlock = subBuilder; + break; + } + case 114: { + global::Miningcore.Blockchain.Kaspa.Kaspad.InvRelayBlockMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.InvRelayBlockMessage(); + if (payloadCase_ == PayloadOneofCase.InvRelayBlock) { + subBuilder.MergeFrom(InvRelayBlock); + } + input.ReadMessage(subBuilder); + InvRelayBlock = subBuilder; + break; + } + case 122: { + global::Miningcore.Blockchain.Kaspa.Kaspad.InvTransactionsMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.InvTransactionsMessage(); + if (payloadCase_ == PayloadOneofCase.InvTransactions) { + subBuilder.MergeFrom(InvTransactions); + } + input.ReadMessage(subBuilder); + InvTransactions = subBuilder; + break; + } + case 130: { + global::Miningcore.Blockchain.Kaspa.Kaspad.PingMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.PingMessage(); + if (payloadCase_ == PayloadOneofCase.Ping) { + subBuilder.MergeFrom(Ping); + } + input.ReadMessage(subBuilder); + Ping = subBuilder; + break; + } + case 138: { + global::Miningcore.Blockchain.Kaspa.Kaspad.PongMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.PongMessage(); + if (payloadCase_ == PayloadOneofCase.Pong) { + subBuilder.MergeFrom(Pong); + } + input.ReadMessage(subBuilder); + Pong = subBuilder; + break; + } + case 154: { + global::Miningcore.Blockchain.Kaspa.Kaspad.VerackMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.VerackMessage(); + if (payloadCase_ == PayloadOneofCase.Verack) { + subBuilder.MergeFrom(Verack); + } + input.ReadMessage(subBuilder); + Verack = subBuilder; + break; + } + case 162: { + global::Miningcore.Blockchain.Kaspa.Kaspad.VersionMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.VersionMessage(); + if (payloadCase_ == PayloadOneofCase.Version) { + subBuilder.MergeFrom(Version); + } + input.ReadMessage(subBuilder); + Version = subBuilder; + break; + } + case 170: { + global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionNotFoundMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionNotFoundMessage(); + if (payloadCase_ == PayloadOneofCase.TransactionNotFound) { + subBuilder.MergeFrom(TransactionNotFound); + } + input.ReadMessage(subBuilder); + TransactionNotFound = subBuilder; + break; + } + case 178: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RejectMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RejectMessage(); + if (payloadCase_ == PayloadOneofCase.Reject) { + subBuilder.MergeFrom(Reject); + } + input.ReadMessage(subBuilder); + Reject = subBuilder; + break; + } + case 202: { + global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUtxoSetChunkMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUtxoSetChunkMessage(); + if (payloadCase_ == PayloadOneofCase.PruningPointUtxoSetChunk) { + subBuilder.MergeFrom(PruningPointUtxoSetChunk); + } + input.ReadMessage(subBuilder); + PruningPointUtxoSetChunk = subBuilder; + break; + } + case 210: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDBlocksMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDBlocksMessage(); + if (payloadCase_ == PayloadOneofCase.RequestIBDBlocks) { + subBuilder.MergeFrom(RequestIBDBlocks); + } + input.ReadMessage(subBuilder); + RequestIBDBlocks = subBuilder; + break; + } + case 218: { + global::Miningcore.Blockchain.Kaspa.Kaspad.UnexpectedPruningPointMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.UnexpectedPruningPointMessage(); + if (payloadCase_ == PayloadOneofCase.UnexpectedPruningPoint) { + subBuilder.MergeFrom(UnexpectedPruningPoint); + } + input.ReadMessage(subBuilder); + UnexpectedPruningPoint = subBuilder; + break; + } + case 242: { + global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorMessage(); + if (payloadCase_ == PayloadOneofCase.IbdBlockLocator) { + subBuilder.MergeFrom(IbdBlockLocator); + } + input.ReadMessage(subBuilder); + IbdBlockLocator = subBuilder; + break; + } + case 250: { + global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashMessage(); + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHash) { + subBuilder.MergeFrom(IbdBlockLocatorHighestHash); + } + input.ReadMessage(subBuilder); + IbdBlockLocatorHighestHash = subBuilder; + break; + } + case 266: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointUtxoSetChunkMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointUtxoSetChunkMessage(); + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointUtxoSetChunk) { + subBuilder.MergeFrom(RequestNextPruningPointUtxoSetChunk); + } + input.ReadMessage(subBuilder); + RequestNextPruningPointUtxoSetChunk = subBuilder; + break; + } + case 274: { + global::Miningcore.Blockchain.Kaspa.Kaspad.DonePruningPointUtxoSetChunksMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.DonePruningPointUtxoSetChunksMessage(); + if (payloadCase_ == PayloadOneofCase.DonePruningPointUtxoSetChunks) { + subBuilder.MergeFrom(DonePruningPointUtxoSetChunks); + } + input.ReadMessage(subBuilder); + DonePruningPointUtxoSetChunks = subBuilder; + break; + } + case 282: { + global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashNotFoundMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashNotFoundMessage(); + if (payloadCase_ == PayloadOneofCase.IbdBlockLocatorHighestHashNotFound) { + subBuilder.MergeFrom(IbdBlockLocatorHighestHashNotFound); + } + input.ReadMessage(subBuilder); + IbdBlockLocatorHighestHashNotFound = subBuilder; + break; + } + case 290: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataMessage(); + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedData) { + subBuilder.MergeFrom(BlockWithTrustedData); + } + input.ReadMessage(subBuilder); + BlockWithTrustedData = subBuilder; + break; + } + case 298: { + global::Miningcore.Blockchain.Kaspa.Kaspad.DoneBlocksWithTrustedDataMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.DoneBlocksWithTrustedDataMessage(); + if (payloadCase_ == PayloadOneofCase.DoneBlocksWithTrustedData) { + subBuilder.MergeFrom(DoneBlocksWithTrustedData); + } + input.ReadMessage(subBuilder); + DoneBlocksWithTrustedData = subBuilder; + break; + } + case 322: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointAndItsAnticoneMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointAndItsAnticoneMessage(); + if (payloadCase_ == PayloadOneofCase.RequestPruningPointAndItsAnticone) { + subBuilder.MergeFrom(RequestPruningPointAndItsAnticone); + } + input.ReadMessage(subBuilder); + RequestPruningPointAndItsAnticone = subBuilder; + break; + } + case 330: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeadersMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeadersMessage(); + if (payloadCase_ == PayloadOneofCase.BlockHeaders) { + subBuilder.MergeFrom(BlockHeaders); + } + input.ReadMessage(subBuilder); + BlockHeaders = subBuilder; + break; + } + case 338: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextHeadersMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextHeadersMessage(); + if (payloadCase_ == PayloadOneofCase.RequestNextHeaders) { + subBuilder.MergeFrom(RequestNextHeaders); + } + input.ReadMessage(subBuilder); + RequestNextHeaders = subBuilder; + break; + } + case 346: { + global::Miningcore.Blockchain.Kaspa.Kaspad.DoneHeadersMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.DoneHeadersMessage(); + if (payloadCase_ == PayloadOneofCase.DoneHeaders) { + subBuilder.MergeFrom(DoneHeaders); + } + input.ReadMessage(subBuilder); + DoneHeaders = subBuilder; + break; + } + case 354: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointUTXOSetMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointUTXOSetMessage(); + if (payloadCase_ == PayloadOneofCase.RequestPruningPointUTXOSet) { + subBuilder.MergeFrom(RequestPruningPointUTXOSet); + } + input.ReadMessage(subBuilder); + RequestPruningPointUTXOSet = subBuilder; + break; + } + case 362: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestHeadersMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestHeadersMessage(); + if (payloadCase_ == PayloadOneofCase.RequestHeaders) { + subBuilder.MergeFrom(RequestHeaders); + } + input.ReadMessage(subBuilder); + RequestHeaders = subBuilder; + break; + } + case 370: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestBlockLocatorMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestBlockLocatorMessage(); + if (payloadCase_ == PayloadOneofCase.RequestBlockLocator) { + subBuilder.MergeFrom(RequestBlockLocator); + } + input.ReadMessage(subBuilder); + RequestBlockLocator = subBuilder; + break; + } + case 378: { + global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointsMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointsMessage(); + if (payloadCase_ == PayloadOneofCase.PruningPoints) { + subBuilder.MergeFrom(PruningPoints); + } + input.ReadMessage(subBuilder); + PruningPoints = subBuilder; + break; + } + case 386: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointProofMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointProofMessage(); + if (payloadCase_ == PayloadOneofCase.RequestPruningPointProof) { + subBuilder.MergeFrom(RequestPruningPointProof); + } + input.ReadMessage(subBuilder); + RequestPruningPointProof = subBuilder; + break; + } + case 394: { + global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofMessage(); + if (payloadCase_ == PayloadOneofCase.PruningPointProof) { + subBuilder.MergeFrom(PruningPointProof); + } + input.ReadMessage(subBuilder); + PruningPointProof = subBuilder; + break; + } + case 402: { + global::Miningcore.Blockchain.Kaspa.Kaspad.ReadyMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.ReadyMessage(); + if (payloadCase_ == PayloadOneofCase.Ready) { + subBuilder.MergeFrom(Ready); + } + input.ReadMessage(subBuilder); + Ready = subBuilder; + break; + } + case 410: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataV4Message subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataV4Message(); + if (payloadCase_ == PayloadOneofCase.BlockWithTrustedDataV4) { + subBuilder.MergeFrom(BlockWithTrustedDataV4); + } + input.ReadMessage(subBuilder); + BlockWithTrustedDataV4 = subBuilder; + break; + } + case 418: { + global::Miningcore.Blockchain.Kaspa.Kaspad.TrustedDataMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.TrustedDataMessage(); + if (payloadCase_ == PayloadOneofCase.TrustedData) { + subBuilder.MergeFrom(TrustedData); + } + input.ReadMessage(subBuilder); + TrustedData = subBuilder; + break; + } + case 426: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDChainBlockLocatorMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDChainBlockLocatorMessage(); + if (payloadCase_ == PayloadOneofCase.RequestIBDChainBlockLocator) { + subBuilder.MergeFrom(RequestIBDChainBlockLocator); + } + input.ReadMessage(subBuilder); + RequestIBDChainBlockLocator = subBuilder; + break; + } + case 434: { + global::Miningcore.Blockchain.Kaspa.Kaspad.IbdChainBlockLocatorMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.IbdChainBlockLocatorMessage(); + if (payloadCase_ == PayloadOneofCase.IbdChainBlockLocator) { + subBuilder.MergeFrom(IbdChainBlockLocator); + } + input.ReadMessage(subBuilder); + IbdChainBlockLocator = subBuilder; + break; + } + case 442: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAnticoneMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAnticoneMessage(); + if (payloadCase_ == PayloadOneofCase.RequestAnticone) { + subBuilder.MergeFrom(RequestAnticone); + } + input.ReadMessage(subBuilder); + RequestAnticone = subBuilder; + break; + } + case 450: { + global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointAndItsAnticoneBlocksMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointAndItsAnticoneBlocksMessage(); + if (payloadCase_ == PayloadOneofCase.RequestNextPruningPointAndItsAnticoneBlocks) { + subBuilder.MergeFrom(RequestNextPruningPointAndItsAnticoneBlocks); + } + input.ReadMessage(subBuilder); + RequestNextPruningPointAndItsAnticoneBlocks = subBuilder; + break; + } + case 8010: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkRequest) { + subBuilder.MergeFrom(GetCurrentNetworkRequest); + } + input.ReadMessage(subBuilder); + GetCurrentNetworkRequest = subBuilder; + break; + } + case 8018: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetCurrentNetworkResponse) { + subBuilder.MergeFrom(GetCurrentNetworkResponse); + } + input.ReadMessage(subBuilder); + GetCurrentNetworkResponse = subBuilder; + break; + } + case 8026: { + global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockRequestMessage(); + if (payloadCase_ == PayloadOneofCase.SubmitBlockRequest) { + subBuilder.MergeFrom(SubmitBlockRequest); + } + input.ReadMessage(subBuilder); + SubmitBlockRequest = subBuilder; + break; + } + case 8034: { + global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage(); + if (payloadCase_ == PayloadOneofCase.SubmitBlockResponse) { + subBuilder.MergeFrom(SubmitBlockResponse); + } + input.ReadMessage(subBuilder); + SubmitBlockResponse = subBuilder; + break; + } + case 8042: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateRequest) { + subBuilder.MergeFrom(GetBlockTemplateRequest); + } + input.ReadMessage(subBuilder); + GetBlockTemplateRequest = subBuilder; + break; + } + case 8050: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockTemplateResponse) { + subBuilder.MergeFrom(GetBlockTemplateResponse); + } + input.ReadMessage(subBuilder); + GetBlockTemplateResponse = subBuilder; + break; + } + case 8058: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedRequest) { + subBuilder.MergeFrom(NotifyBlockAddedRequest); + } + input.ReadMessage(subBuilder); + NotifyBlockAddedRequest = subBuilder; + break; + } + case 8066: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyBlockAddedResponse) { + subBuilder.MergeFrom(NotifyBlockAddedResponse); + } + input.ReadMessage(subBuilder); + NotifyBlockAddedResponse = subBuilder; + break; + } + case 8074: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BlockAddedNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockAddedNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.BlockAddedNotification) { + subBuilder.MergeFrom(BlockAddedNotification); + } + input.ReadMessage(subBuilder); + BlockAddedNotification = subBuilder; + break; + } + case 8082: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesRequest) { + subBuilder.MergeFrom(GetPeerAddressesRequest); + } + input.ReadMessage(subBuilder); + GetPeerAddressesRequest = subBuilder; + break; + } + case 8090: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetPeerAddressesResponse) { + subBuilder.MergeFrom(GetPeerAddressesResponse); + } + input.ReadMessage(subBuilder); + GetPeerAddressesResponse = subBuilder; + break; + } + case 8098: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashRequest) { + subBuilder.MergeFrom(GetSelectedTipHashRequest); + } + input.ReadMessage(subBuilder); + GetSelectedTipHashRequest = subBuilder; + break; + } + case 8106: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetSelectedTipHashResponse) { + subBuilder.MergeFrom(GetSelectedTipHashResponse); + } + input.ReadMessage(subBuilder); + GetSelectedTipHashResponse = subBuilder; + break; + } + case 8114: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryRequest) { + subBuilder.MergeFrom(GetMempoolEntryRequest); + } + input.ReadMessage(subBuilder); + GetMempoolEntryRequest = subBuilder; + break; + } + case 8122: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntryResponse) { + subBuilder.MergeFrom(GetMempoolEntryResponse); + } + input.ReadMessage(subBuilder); + GetMempoolEntryResponse = subBuilder; + break; + } + case 8130: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoRequest) { + subBuilder.MergeFrom(GetConnectedPeerInfoRequest); + } + input.ReadMessage(subBuilder); + GetConnectedPeerInfoRequest = subBuilder; + break; + } + case 8138: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetConnectedPeerInfoResponse) { + subBuilder.MergeFrom(GetConnectedPeerInfoResponse); + } + input.ReadMessage(subBuilder); + GetConnectedPeerInfoResponse = subBuilder; + break; + } + case 8146: { + global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerRequestMessage(); + if (payloadCase_ == PayloadOneofCase.AddPeerRequest) { + subBuilder.MergeFrom(AddPeerRequest); + } + input.ReadMessage(subBuilder); + AddPeerRequest = subBuilder; + break; + } + case 8154: { + global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerResponseMessage(); + if (payloadCase_ == PayloadOneofCase.AddPeerResponse) { + subBuilder.MergeFrom(AddPeerResponse); + } + input.ReadMessage(subBuilder); + AddPeerResponse = subBuilder; + break; + } + case 8162: { + global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionRequestMessage(); + if (payloadCase_ == PayloadOneofCase.SubmitTransactionRequest) { + subBuilder.MergeFrom(SubmitTransactionRequest); + } + input.ReadMessage(subBuilder); + SubmitTransactionRequest = subBuilder; + break; + } + case 8170: { + global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionResponseMessage(); + if (payloadCase_ == PayloadOneofCase.SubmitTransactionResponse) { + subBuilder.MergeFrom(SubmitTransactionResponse); + } + input.ReadMessage(subBuilder); + SubmitTransactionResponse = subBuilder; + break; + } + case 8178: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedRequest) { + subBuilder.MergeFrom(NotifyVirtualSelectedParentChainChangedRequest); + } + input.ReadMessage(subBuilder); + NotifyVirtualSelectedParentChainChangedRequest = subBuilder; + break; + } + case 8186: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentChainChangedResponse) { + subBuilder.MergeFrom(NotifyVirtualSelectedParentChainChangedResponse); + } + input.ReadMessage(subBuilder); + NotifyVirtualSelectedParentChainChangedResponse = subBuilder; + break; + } + case 8194: { + global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentChainChangedNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentChainChangedNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentChainChangedNotification) { + subBuilder.MergeFrom(VirtualSelectedParentChainChangedNotification); + } + input.ReadMessage(subBuilder); + VirtualSelectedParentChainChangedNotification = subBuilder; + break; + } + case 8202: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockRequest) { + subBuilder.MergeFrom(GetBlockRequest); + } + input.ReadMessage(subBuilder); + GetBlockRequest = subBuilder; + break; + } + case 8210: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockResponse) { + subBuilder.MergeFrom(GetBlockResponse); + } + input.ReadMessage(subBuilder); + GetBlockResponse = subBuilder; + break; + } + case 8218: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetSubnetworkRequest) { + subBuilder.MergeFrom(GetSubnetworkRequest); + } + input.ReadMessage(subBuilder); + GetSubnetworkRequest = subBuilder; + break; + } + case 8226: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetSubnetworkResponse) { + subBuilder.MergeFrom(GetSubnetworkResponse); + } + input.ReadMessage(subBuilder); + GetSubnetworkResponse = subBuilder; + break; + } + case 8234: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockRequest) { + subBuilder.MergeFrom(GetVirtualSelectedParentChainFromBlockRequest); + } + input.ReadMessage(subBuilder); + GetVirtualSelectedParentChainFromBlockRequest = subBuilder; + break; + } + case 8242: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentChainFromBlockResponse) { + subBuilder.MergeFrom(GetVirtualSelectedParentChainFromBlockResponse); + } + input.ReadMessage(subBuilder); + GetVirtualSelectedParentChainFromBlockResponse = subBuilder; + break; + } + case 8250: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlocksRequest) { + subBuilder.MergeFrom(GetBlocksRequest); + } + input.ReadMessage(subBuilder); + GetBlocksRequest = subBuilder; + break; + } + case 8258: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlocksResponse) { + subBuilder.MergeFrom(GetBlocksResponse); + } + input.ReadMessage(subBuilder); + GetBlocksResponse = subBuilder; + break; + } + case 8266: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockCountRequest) { + subBuilder.MergeFrom(GetBlockCountRequest); + } + input.ReadMessage(subBuilder); + GetBlockCountRequest = subBuilder; + break; + } + case 8274: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockCountResponse) { + subBuilder.MergeFrom(GetBlockCountResponse); + } + input.ReadMessage(subBuilder); + GetBlockCountResponse = subBuilder; + break; + } + case 8282: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoRequest) { + subBuilder.MergeFrom(GetBlockDagInfoRequest); + } + input.ReadMessage(subBuilder); + GetBlockDagInfoRequest = subBuilder; + break; + } + case 8290: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetBlockDagInfoResponse) { + subBuilder.MergeFrom(GetBlockDagInfoResponse); + } + input.ReadMessage(subBuilder); + GetBlockDagInfoResponse = subBuilder; + break; + } + case 8298: { + global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictRequestMessage(); + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictRequest) { + subBuilder.MergeFrom(ResolveFinalityConflictRequest); + } + input.ReadMessage(subBuilder); + ResolveFinalityConflictRequest = subBuilder; + break; + } + case 8306: { + global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictResponseMessage(); + if (payloadCase_ == PayloadOneofCase.ResolveFinalityConflictResponse) { + subBuilder.MergeFrom(ResolveFinalityConflictResponse); + } + input.ReadMessage(subBuilder); + ResolveFinalityConflictResponse = subBuilder; + break; + } + case 8314: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsRequest) { + subBuilder.MergeFrom(NotifyFinalityConflictsRequest); + } + input.ReadMessage(subBuilder); + NotifyFinalityConflictsRequest = subBuilder; + break; + } + case 8322: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyFinalityConflictsResponse) { + subBuilder.MergeFrom(NotifyFinalityConflictsResponse); + } + input.ReadMessage(subBuilder); + NotifyFinalityConflictsResponse = subBuilder; + break; + } + case 8330: { + global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.FinalityConflictNotification) { + subBuilder.MergeFrom(FinalityConflictNotification); + } + input.ReadMessage(subBuilder); + FinalityConflictNotification = subBuilder; + break; + } + case 8338: { + global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictResolvedNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictResolvedNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.FinalityConflictResolvedNotification) { + subBuilder.MergeFrom(FinalityConflictResolvedNotification); + } + input.ReadMessage(subBuilder); + FinalityConflictResolvedNotification = subBuilder; + break; + } + case 8346: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesRequest) { + subBuilder.MergeFrom(GetMempoolEntriesRequest); + } + input.ReadMessage(subBuilder); + GetMempoolEntriesRequest = subBuilder; + break; + } + case 8354: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesResponse) { + subBuilder.MergeFrom(GetMempoolEntriesResponse); + } + input.ReadMessage(subBuilder); + GetMempoolEntriesResponse = subBuilder; + break; + } + case 8362: { + global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownRequestMessage(); + if (payloadCase_ == PayloadOneofCase.ShutDownRequest) { + subBuilder.MergeFrom(ShutDownRequest); + } + input.ReadMessage(subBuilder); + ShutDownRequest = subBuilder; + break; + } + case 8370: { + global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownResponseMessage(); + if (payloadCase_ == PayloadOneofCase.ShutDownResponse) { + subBuilder.MergeFrom(ShutDownResponse); + } + input.ReadMessage(subBuilder); + ShutDownResponse = subBuilder; + break; + } + case 8378: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetHeadersRequest) { + subBuilder.MergeFrom(GetHeadersRequest); + } + input.ReadMessage(subBuilder); + GetHeadersRequest = subBuilder; + break; + } + case 8386: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetHeadersResponse) { + subBuilder.MergeFrom(GetHeadersResponse); + } + input.ReadMessage(subBuilder); + GetHeadersResponse = subBuilder; + break; + } + case 8394: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedRequest) { + subBuilder.MergeFrom(NotifyUtxosChangedRequest); + } + input.ReadMessage(subBuilder); + NotifyUtxosChangedRequest = subBuilder; + break; + } + case 8402: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyUtxosChangedResponse) { + subBuilder.MergeFrom(NotifyUtxosChangedResponse); + } + input.ReadMessage(subBuilder); + NotifyUtxosChangedResponse = subBuilder; + break; + } + case 8410: { + global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosChangedNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosChangedNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.UtxosChangedNotification) { + subBuilder.MergeFrom(UtxosChangedNotification); + } + input.ReadMessage(subBuilder); + UtxosChangedNotification = subBuilder; + break; + } + case 8418: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesRequest) { + subBuilder.MergeFrom(GetUtxosByAddressesRequest); + } + input.ReadMessage(subBuilder); + GetUtxosByAddressesRequest = subBuilder; + break; + } + case 8426: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetUtxosByAddressesResponse) { + subBuilder.MergeFrom(GetUtxosByAddressesResponse); + } + input.ReadMessage(subBuilder); + GetUtxosByAddressesResponse = subBuilder; + break; + } + case 8434: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreRequest) { + subBuilder.MergeFrom(GetVirtualSelectedParentBlueScoreRequest); + } + input.ReadMessage(subBuilder); + GetVirtualSelectedParentBlueScoreRequest = subBuilder; + break; + } + case 8442: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetVirtualSelectedParentBlueScoreResponse) { + subBuilder.MergeFrom(GetVirtualSelectedParentBlueScoreResponse); + } + input.ReadMessage(subBuilder); + GetVirtualSelectedParentBlueScoreResponse = subBuilder; + break; + } + case 8450: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedRequest) { + subBuilder.MergeFrom(NotifyVirtualSelectedParentBlueScoreChangedRequest); + } + input.ReadMessage(subBuilder); + NotifyVirtualSelectedParentBlueScoreChangedRequest = subBuilder; + break; + } + case 8458: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualSelectedParentBlueScoreChangedResponse) { + subBuilder.MergeFrom(NotifyVirtualSelectedParentBlueScoreChangedResponse); + } + input.ReadMessage(subBuilder); + NotifyVirtualSelectedParentBlueScoreChangedResponse = subBuilder; + break; + } + case 8466: { + global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentBlueScoreChangedNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentBlueScoreChangedNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.VirtualSelectedParentBlueScoreChangedNotification) { + subBuilder.MergeFrom(VirtualSelectedParentBlueScoreChangedNotification); + } + input.ReadMessage(subBuilder); + VirtualSelectedParentBlueScoreChangedNotification = subBuilder; + break; + } + case 8474: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BanRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BanRequestMessage(); + if (payloadCase_ == PayloadOneofCase.BanRequest) { + subBuilder.MergeFrom(BanRequest); + } + input.ReadMessage(subBuilder); + BanRequest = subBuilder; + break; + } + case 8482: { + global::Miningcore.Blockchain.Kaspa.Kaspad.BanResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.BanResponseMessage(); + if (payloadCase_ == PayloadOneofCase.BanResponse) { + subBuilder.MergeFrom(BanResponse); + } + input.ReadMessage(subBuilder); + BanResponse = subBuilder; + break; + } + case 8490: { + global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanRequestMessage(); + if (payloadCase_ == PayloadOneofCase.UnbanRequest) { + subBuilder.MergeFrom(UnbanRequest); + } + input.ReadMessage(subBuilder); + UnbanRequest = subBuilder; + break; + } + case 8498: { + global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanResponseMessage(); + if (payloadCase_ == PayloadOneofCase.UnbanResponse) { + subBuilder.MergeFrom(UnbanResponse); + } + input.ReadMessage(subBuilder); + UnbanResponse = subBuilder; + break; + } + case 8506: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetInfoRequest) { + subBuilder.MergeFrom(GetInfoRequest); + } + input.ReadMessage(subBuilder); + GetInfoRequest = subBuilder; + break; + } + case 8514: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetInfoResponse) { + subBuilder.MergeFrom(GetInfoResponse); + } + input.ReadMessage(subBuilder); + GetInfoResponse = subBuilder; + break; + } + case 8522: { + global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedRequestMessage(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedRequest) { + subBuilder.MergeFrom(StopNotifyingUtxosChangedRequest); + } + input.ReadMessage(subBuilder); + StopNotifyingUtxosChangedRequest = subBuilder; + break; + } + case 8530: { + global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedResponseMessage(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingUtxosChangedResponse) { + subBuilder.MergeFrom(StopNotifyingUtxosChangedResponse); + } + input.ReadMessage(subBuilder); + StopNotifyingUtxosChangedResponse = subBuilder; + break; + } + case 8538: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideRequest) { + subBuilder.MergeFrom(NotifyPruningPointUTXOSetOverrideRequest); + } + input.ReadMessage(subBuilder); + NotifyPruningPointUTXOSetOverrideRequest = subBuilder; + break; + } + case 8546: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyPruningPointUTXOSetOverrideResponse) { + subBuilder.MergeFrom(NotifyPruningPointUTXOSetOverrideResponse); + } + input.ReadMessage(subBuilder); + NotifyPruningPointUTXOSetOverrideResponse = subBuilder; + break; + } + case 8554: { + global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUTXOSetOverrideNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUTXOSetOverrideNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.PruningPointUTXOSetOverrideNotification) { + subBuilder.MergeFrom(PruningPointUTXOSetOverrideNotification); + } + input.ReadMessage(subBuilder); + PruningPointUTXOSetOverrideNotification = subBuilder; + break; + } + case 8562: { + global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideRequestMessage(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideRequest) { + subBuilder.MergeFrom(StopNotifyingPruningPointUTXOSetOverrideRequest); + } + input.ReadMessage(subBuilder); + StopNotifyingPruningPointUTXOSetOverrideRequest = subBuilder; + break; + } + case 8570: { + global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideResponseMessage(); + if (payloadCase_ == PayloadOneofCase.StopNotifyingPruningPointUTXOSetOverrideResponse) { + subBuilder.MergeFrom(StopNotifyingPruningPointUTXOSetOverrideResponse); + } + input.ReadMessage(subBuilder); + StopNotifyingPruningPointUTXOSetOverrideResponse = subBuilder; + break; + } + case 8578: { + global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondRequestMessage(); + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondRequest) { + subBuilder.MergeFrom(EstimateNetworkHashesPerSecondRequest); + } + input.ReadMessage(subBuilder); + EstimateNetworkHashesPerSecondRequest = subBuilder; + break; + } + case 8586: { + global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondResponseMessage(); + if (payloadCase_ == PayloadOneofCase.EstimateNetworkHashesPerSecondResponse) { + subBuilder.MergeFrom(EstimateNetworkHashesPerSecondResponse); + } + input.ReadMessage(subBuilder); + EstimateNetworkHashesPerSecondResponse = subBuilder; + break; + } + case 8594: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedRequest) { + subBuilder.MergeFrom(NotifyVirtualDaaScoreChangedRequest); + } + input.ReadMessage(subBuilder); + NotifyVirtualDaaScoreChangedRequest = subBuilder; + break; + } + case 8602: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyVirtualDaaScoreChangedResponse) { + subBuilder.MergeFrom(NotifyVirtualDaaScoreChangedResponse); + } + input.ReadMessage(subBuilder); + NotifyVirtualDaaScoreChangedResponse = subBuilder; + break; + } + case 8610: { + global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualDaaScoreChangedNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualDaaScoreChangedNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.VirtualDaaScoreChangedNotification) { + subBuilder.MergeFrom(VirtualDaaScoreChangedNotification); + } + input.ReadMessage(subBuilder); + VirtualDaaScoreChangedNotification = subBuilder; + break; + } + case 8618: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressRequest) { + subBuilder.MergeFrom(GetBalanceByAddressRequest); + } + input.ReadMessage(subBuilder); + GetBalanceByAddressRequest = subBuilder; + break; + } + case 8626: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetBalanceByAddressResponse) { + subBuilder.MergeFrom(GetBalanceByAddressResponse); + } + input.ReadMessage(subBuilder); + GetBalanceByAddressResponse = subBuilder; + break; + } + case 8634: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesRequest) { + subBuilder.MergeFrom(GetBalancesByAddressesRequest); + } + input.ReadMessage(subBuilder); + GetBalancesByAddressesRequest = subBuilder; + break; + } + case 8642: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetBalancesByAddressesResponse) { + subBuilder.MergeFrom(GetBalancesByAddressesResponse); + } + input.ReadMessage(subBuilder); + GetBalancesByAddressesResponse = subBuilder; + break; + } + case 8650: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateRequestMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateRequest) { + subBuilder.MergeFrom(NotifyNewBlockTemplateRequest); + } + input.ReadMessage(subBuilder); + NotifyNewBlockTemplateRequest = subBuilder; + break; + } + case 8658: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateResponseMessage(); + if (payloadCase_ == PayloadOneofCase.NotifyNewBlockTemplateResponse) { + subBuilder.MergeFrom(NotifyNewBlockTemplateResponse); + } + input.ReadMessage(subBuilder); + NotifyNewBlockTemplateResponse = subBuilder; + break; + } + case 8666: { + global::Miningcore.Blockchain.Kaspa.Kaspad.NewBlockTemplateNotificationMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.NewBlockTemplateNotificationMessage(); + if (payloadCase_ == PayloadOneofCase.NewBlockTemplateNotification) { + subBuilder.MergeFrom(NewBlockTemplateNotification); + } + input.ReadMessage(subBuilder); + NewBlockTemplateNotification = subBuilder; + break; + } + case 8674: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesRequest) { + subBuilder.MergeFrom(GetMempoolEntriesByAddressesRequest); + } + input.ReadMessage(subBuilder); + GetMempoolEntriesByAddressesRequest = subBuilder; + break; + } + case 8682: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetMempoolEntriesByAddressesResponse) { + subBuilder.MergeFrom(GetMempoolEntriesByAddressesResponse); + } + input.ReadMessage(subBuilder); + GetMempoolEntriesByAddressesResponse = subBuilder; + break; + } + case 8690: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyRequestMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyRequestMessage(); + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyRequest) { + subBuilder.MergeFrom(GetCoinSupplyRequest); + } + input.ReadMessage(subBuilder); + GetCoinSupplyRequest = subBuilder; + break; + } + case 8698: { + global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyResponseMessage subBuilder = new global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyResponseMessage(); + if (payloadCase_ == PayloadOneofCase.GetCoinSupplyResponse) { + subBuilder.MergeFrom(GetCoinSupplyResponse); + } + input.ReadMessage(subBuilder); + GetCoinSupplyResponse = subBuilder; + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/MessagesGrpc.cs b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/MessagesGrpc.cs new file mode 100644 index 000000000..a435679f9 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/MessagesGrpc.cs @@ -0,0 +1,236 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: RPC/Kaspad/messages.proto +// +// Original file comments: +// https://raw.githubusercontent.com/kaspanet/kaspad/master/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +// RPC-related types. Request messages, response messages, and dependant types. +// +// Clients are expected to build RequestMessages and wrap them in KaspadMessage. (see messages.proto) +// +// Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a +// ResponseMessage (likewise wrapped in a KaspadMessage) respective to the original RequestMessage. +// +// **IMPORTANT:** This API is a work in progress and is subject to break between versions. +// +#pragma warning disable 0414, 1591, 8981, 0612 +#region Designer generated code + +namespace Miningcore.Blockchain.Kaspa.Kaspad { + + using grpc = global::Grpc.Core; + + public partial class KaspadP2P + { + public KaspadP2P(string __ServiceName) + { + this.__Method_MessageStream = new grpc::Method( + grpc::MethodType.DuplexStreaming, + __ServiceName, + "MessageStream", + __Marshaller_protowire_KaspadMessage, + __Marshaller_protowire_KaspadMessage); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context) + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (message is global::Google.Protobuf.IBufferMessage) + { + context.SetPayloadLength(message.CalculateSize()); + global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter()); + context.Complete(); + return; + } + #endif + context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static class __Helper_MessageCache + { + public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static T __Helper_DeserializeMessage(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser parser) where T : global::Google.Protobuf.IMessage + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (__Helper_MessageCache.IsBufferMessage) + { + return parser.ParseFrom(context.PayloadAsReadOnlySequence()); + } + #endif + return parser.ParseFrom(context.PayloadAsNewBuffer()); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_protowire_KaspadMessage = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.Kaspad.KaspadMessage.Parser)); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_MessageStream { get; private set; } + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Miningcore.Blockchain.Kaspa.Kaspad.MessagesReflection.Descriptor.Services[0]; } + } + + /// Client for KaspadP2P + public partial class KaspadP2PClient : grpc::ClientBase + { + public KaspadP2P __KaspadP2P { get; private set; } + + /// Creates a new client for KaspadP2P + /// The channel to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public KaspadP2PClient(KaspadP2P __KaspadP2P, grpc::ChannelBase channel) : base(channel) + { + this.__KaspadP2P = __KaspadP2P; + } + /// Creates a new client for KaspadP2P that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public KaspadP2PClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected KaspadP2PClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected KaspadP2PClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncDuplexStreamingCall MessageStream(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return MessageStream(new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncDuplexStreamingCall MessageStream(grpc::CallOptions options) + { + return CallInvoker.AsyncDuplexStreamingCall(__KaspadP2P.__Method_MessageStream, null, options); + } + /// Creates a new instance of client from given KaspadP2P, ClientBaseConfiguration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected override KaspadP2PClient NewInstance(ClientBaseConfiguration configuration) + { + return new KaspadP2PClient(configuration); + } + } + + } + public partial class KaspadRPC + { + public KaspadRPC(string __ServiceName) + { + this.__Method_MessageStream = new grpc::Method( + grpc::MethodType.DuplexStreaming, + __ServiceName, + "MessageStream", + __Marshaller_protowire_KaspadMessage, + __Marshaller_protowire_KaspadMessage); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static void __Helper_SerializeMessage(global::Google.Protobuf.IMessage message, grpc::SerializationContext context) + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (message is global::Google.Protobuf.IBufferMessage) + { + context.SetPayloadLength(message.CalculateSize()); + global::Google.Protobuf.MessageExtensions.WriteTo(message, context.GetBufferWriter()); + context.Complete(); + return; + } + #endif + context.Complete(global::Google.Protobuf.MessageExtensions.ToByteArray(message)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static class __Helper_MessageCache + { + public static readonly bool IsBufferMessage = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(global::Google.Protobuf.IBufferMessage)).IsAssignableFrom(typeof(T)); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static T __Helper_DeserializeMessage(grpc::DeserializationContext context, global::Google.Protobuf.MessageParser parser) where T : global::Google.Protobuf.IMessage + { + #if !GRPC_DISABLE_PROTOBUF_BUFFER_SERIALIZATION + if (__Helper_MessageCache.IsBufferMessage) + { + return parser.ParseFrom(context.PayloadAsReadOnlySequence()); + } + #endif + return parser.ParseFrom(context.PayloadAsNewBuffer()); + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + static readonly grpc::Marshaller __Marshaller_protowire_KaspadMessage = grpc::Marshallers.Create(__Helper_SerializeMessage, context => __Helper_DeserializeMessage(context, global::Miningcore.Blockchain.Kaspa.Kaspad.KaspadMessage.Parser)); + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public grpc::Method __Method_MessageStream { get; private set; } + + /// Service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Miningcore.Blockchain.Kaspa.Kaspad.MessagesReflection.Descriptor.Services[1]; } + } + + /// Client for KaspadRPC + public partial class KaspadRPCClient : grpc::ClientBase + { + public KaspadRPC __KaspadRPC { get; private set; } + + /// Creates a new client for KaspadRPC + /// The channel to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public KaspadRPCClient(KaspadRPC __KaspadRPC, grpc::ChannelBase channel) : base(channel) + { + this.__KaspadRPC = __KaspadRPC; + } + /// Creates a new client for KaspadRPC that uses a custom CallInvoker. + /// The callInvoker to use to make remote calls. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public KaspadRPCClient(grpc::CallInvoker callInvoker) : base(callInvoker) + { + } + /// Protected parameterless constructor to allow creation of test doubles. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected KaspadRPCClient() : base() + { + } + /// Protected constructor to allow creation of configured clients. + /// The client configuration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected KaspadRPCClient(ClientBaseConfiguration configuration) : base(configuration) + { + } + + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncDuplexStreamingCall MessageStream(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) + { + return MessageStream(new grpc::CallOptions(headers, deadline, cancellationToken)); + } + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + public virtual grpc::AsyncDuplexStreamingCall MessageStream(grpc::CallOptions options) + { + return CallInvoker.AsyncDuplexStreamingCall(__KaspadRPC.__Method_MessageStream, null, options); + } + /// Creates a new instance of client from given ClientBaseConfiguration. + [global::System.CodeDom.Compiler.GeneratedCode("grpc_csharp_plugin", null)] + protected override KaspadRPCClient NewInstance(ClientBaseConfiguration configuration) + { + return new KaspadRPCClient(configuration); + } + } + + } +} +#endregion diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs new file mode 100644 index 000000000..c5adf4cdc --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/P2P.cs @@ -0,0 +1,9278 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: p2p.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +namespace Miningcore.Blockchain.Kaspa.Kaspad { + + using pb = global::Google.Protobuf; + using pbc = global::Google.Protobuf.Collections; + using pbr = global::Google.Protobuf.Reflection; + using scg = global::System.Collections.Generic; + + /// Holder for reflection information generated from p2p.proto + public static partial class P2PReflection { + + #region Descriptor + /// File descriptor for p2p.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static P2PReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CglwMnAucHJvdG8SCXByb3Rvd2lyZSJnChdSZXF1ZXN0QWRkcmVzc2VzTWVz", + "c2FnZRIdChVpbmNsdWRlQWxsU3VibmV0d29ya3MYASABKAgSLQoMc3VibmV0", + "d29ya0lkGAIgASgLMhcucHJvdG93aXJlLlN1Ym5ldHdvcmtJZCI+ChBBZGRy", + "ZXNzZXNNZXNzYWdlEioKC2FkZHJlc3NMaXN0GAEgAygLMhUucHJvdG93aXJl", + "Lk5ldEFkZHJlc3MiOQoKTmV0QWRkcmVzcxIRCgl0aW1lc3RhbXAYASABKAMS", + "CgoCaXAYAyABKAwSDAoEcG9ydBgEIAEoDSIdCgxTdWJuZXR3b3JrSWQSDQoF", + "Ynl0ZXMYASABKAwi4AEKElRyYW5zYWN0aW9uTWVzc2FnZRIPCgd2ZXJzaW9u", + "GAEgASgNEisKBmlucHV0cxgCIAMoCzIbLnByb3Rvd2lyZS5UcmFuc2FjdGlv", + "bklucHV0Ei0KB291dHB1dHMYAyADKAsyHC5wcm90b3dpcmUuVHJhbnNhY3Rp", + "b25PdXRwdXQSEAoIbG9ja1RpbWUYBCABKAQSLQoMc3VibmV0d29ya0lkGAUg", + "ASgLMhcucHJvdG93aXJlLlN1Ym5ldHdvcmtJZBILCgNnYXMYBiABKAQSDwoH", + "cGF5bG9hZBgIIAEoDCKAAQoQVHJhbnNhY3Rpb25JbnB1dBItChBwcmV2aW91", + "c091dHBvaW50GAEgASgLMhMucHJvdG93aXJlLk91dHBvaW50EhcKD3NpZ25h", + "dHVyZVNjcmlwdBgCIAEoDBIQCghzZXF1ZW5jZRgDIAEoBBISCgpzaWdPcENv", + "dW50GAQgASgNIkoKCE91dHBvaW50Ei8KDXRyYW5zYWN0aW9uSWQYASABKAsy", + "GC5wcm90b3dpcmUuVHJhbnNhY3Rpb25JZBINCgVpbmRleBgCIAEoDSIeCg1U", + "cmFuc2FjdGlvbklkEg0KBWJ5dGVzGAEgASgMIjIKD1NjcmlwdFB1YmxpY0tl", + "eRIOCgZzY3JpcHQYASABKAwSDwoHdmVyc2lvbhgCIAEoDSJXChFUcmFuc2Fj", + "dGlvbk91dHB1dBINCgV2YWx1ZRgBIAEoBBIzCg9zY3JpcHRQdWJsaWNLZXkY", + "AiABKAsyGi5wcm90b3dpcmUuU2NyaXB0UHVibGljS2V5ImsKDEJsb2NrTWVz", + "c2FnZRImCgZoZWFkZXIYASABKAsyFi5wcm90b3dpcmUuQmxvY2tIZWFkZXIS", + "MwoMdHJhbnNhY3Rpb25zGAIgAygLMh0ucHJvdG93aXJlLlRyYW5zYWN0aW9u", + "TWVzc2FnZSLcAgoLQmxvY2tIZWFkZXISDwoHdmVyc2lvbhgBIAEoDRItCgdw", + "YXJlbnRzGAwgAygLMhwucHJvdG93aXJlLkJsb2NrTGV2ZWxQYXJlbnRzEicK", + "Dmhhc2hNZXJrbGVSb290GAMgASgLMg8ucHJvdG93aXJlLkhhc2gSLQoUYWNj", + "ZXB0ZWRJZE1lcmtsZVJvb3QYBCABKAsyDy5wcm90b3dpcmUuSGFzaBInCg51", + "dHhvQ29tbWl0bWVudBgFIAEoCzIPLnByb3Rvd2lyZS5IYXNoEhEKCXRpbWVz", + "dGFtcBgGIAEoAxIMCgRiaXRzGAcgASgNEg0KBW5vbmNlGAggASgEEhAKCGRh", + "YVNjb3JlGAkgASgEEhAKCGJsdWVXb3JrGAogASgMEiUKDHBydW5pbmdQb2lu", + "dBgOIAEoCzIPLnByb3Rvd2lyZS5IYXNoEhEKCWJsdWVTY29yZRgNIAEoBCI6", + "ChFCbG9ja0xldmVsUGFyZW50cxIlCgxwYXJlbnRIYXNoZXMYASADKAsyDy5w", + "cm90b3dpcmUuSGFzaCIVCgRIYXNoEg0KBWJ5dGVzGAEgASgMIk4KGlJlcXVl", + "c3RCbG9ja0xvY2F0b3JNZXNzYWdlEiEKCGhpZ2hIYXNoGAEgASgLMg8ucHJv", + "dG93aXJlLkhhc2gSDQoFbGltaXQYAiABKA0iNgoTQmxvY2tMb2NhdG9yTWVz", + "c2FnZRIfCgZoYXNoZXMYASADKAsyDy5wcm90b3dpcmUuSGFzaCJcChVSZXF1", + "ZXN0SGVhZGVyc01lc3NhZ2USIAoHbG93SGFzaBgBIAEoCzIPLnByb3Rvd2ly", + "ZS5IYXNoEiEKCGhpZ2hIYXNoGAIgASgLMg8ucHJvdG93aXJlLkhhc2giGwoZ", + "UmVxdWVzdE5leHRIZWFkZXJzTWVzc2FnZSIUChJEb25lSGVhZGVyc01lc3Nh", + "Z2UiPAoZUmVxdWVzdFJlbGF5QmxvY2tzTWVzc2FnZRIfCgZoYXNoZXMYASAD", + "KAsyDy5wcm90b3dpcmUuSGFzaCJDChpSZXF1ZXN0VHJhbnNhY3Rpb25zTWVz", + "c2FnZRIlCgNpZHMYASADKAsyGC5wcm90b3dpcmUuVHJhbnNhY3Rpb25JZCJC", + "ChpUcmFuc2FjdGlvbk5vdEZvdW5kTWVzc2FnZRIkCgJpZBgBIAEoCzIYLnBy", + "b3Rvd2lyZS5UcmFuc2FjdGlvbklkIjUKFEludlJlbGF5QmxvY2tNZXNzYWdl", + "Eh0KBGhhc2gYASABKAsyDy5wcm90b3dpcmUuSGFzaCI/ChZJbnZUcmFuc2Fj", + "dGlvbnNNZXNzYWdlEiUKA2lkcxgBIAMoCzIYLnByb3Rvd2lyZS5UcmFuc2Fj", + "dGlvbklkIhwKC1BpbmdNZXNzYWdlEg0KBW5vbmNlGAEgASgEIhwKC1BvbmdN", + "ZXNzYWdlEg0KBW5vbmNlGAEgASgEIg8KDVZlcmFja01lc3NhZ2Ui7QEKDlZl", + "cnNpb25NZXNzYWdlEhcKD3Byb3RvY29sVmVyc2lvbhgBIAEoDRIQCghzZXJ2", + "aWNlcxgCIAEoBBIRCgl0aW1lc3RhbXAYAyABKAMSJgoHYWRkcmVzcxgEIAEo", + "CzIVLnByb3Rvd2lyZS5OZXRBZGRyZXNzEgoKAmlkGAUgASgMEhEKCXVzZXJB", + "Z2VudBgGIAEoCRIWCg5kaXNhYmxlUmVsYXlUeBgIIAEoCBItCgxzdWJuZXR3", + "b3JrSWQYCSABKAsyFy5wcm90b3dpcmUuU3VibmV0d29ya0lkEg8KB25ldHdv", + "cmsYCiABKAkiHwoNUmVqZWN0TWVzc2FnZRIOCgZyZWFzb24YASABKAkiTgoh", + "UmVxdWVzdFBydW5pbmdQb2ludFVUWE9TZXRNZXNzYWdlEikKEHBydW5pbmdQ", + "b2ludEhhc2gYASABKAsyDy5wcm90b3dpcmUuSGFzaCJpCh9QcnVuaW5nUG9p", + "bnRVdHhvU2V0Q2h1bmtNZXNzYWdlEkYKGW91dHBvaW50QW5kVXR4b0VudHJ5", + "UGFpcnMYASADKAsyIy5wcm90b3dpcmUuT3V0cG9pbnRBbmRVdHhvRW50cnlQ", + "YWlyImoKGE91dHBvaW50QW5kVXR4b0VudHJ5UGFpchIlCghvdXRwb2ludBgB", + "IAEoCzITLnByb3Rvd2lyZS5PdXRwb2ludBInCgl1dHhvRW50cnkYAiABKAsy", + "FC5wcm90b3dpcmUuVXR4b0VudHJ5InsKCVV0eG9FbnRyeRIOCgZhbW91bnQY", + "ASABKAQSMwoPc2NyaXB0UHVibGljS2V5GAIgASgLMhoucHJvdG93aXJlLlNj", + "cmlwdFB1YmxpY0tleRIVCg1ibG9ja0RhYVNjb3JlGAMgASgEEhIKCmlzQ29p", + "bmJhc2UYBCABKAgiLAoqUmVxdWVzdE5leHRQcnVuaW5nUG9pbnRVdHhvU2V0", + "Q2h1bmtNZXNzYWdlIiYKJERvbmVQcnVuaW5nUG9pbnRVdHhvU2V0Q2h1bmtz", + "TWVzc2FnZSI6ChdSZXF1ZXN0SUJEQmxvY2tzTWVzc2FnZRIfCgZoYXNoZXMY", + "ASADKAsyDy5wcm90b3dpcmUuSGFzaCIfCh1VbmV4cGVjdGVkUHJ1bmluZ1Bv", + "aW50TWVzc2FnZSJqChZJYmRCbG9ja0xvY2F0b3JNZXNzYWdlEiMKCnRhcmdl", + "dEhhc2gYASABKAsyDy5wcm90b3dpcmUuSGFzaBIrChJibG9ja0xvY2F0b3JI", + "YXNoZXMYAiADKAsyDy5wcm90b3dpcmUuSGFzaCJpCiJSZXF1ZXN0SUJEQ2hh", + "aW5CbG9ja0xvY2F0b3JNZXNzYWdlEiAKB2xvd0hhc2gYASABKAsyDy5wcm90", + "b3dpcmUuSGFzaBIhCghoaWdoSGFzaBgCIAEoCzIPLnByb3Rvd2lyZS5IYXNo", + "IkoKG0liZENoYWluQmxvY2tMb2NhdG9yTWVzc2FnZRIrChJibG9ja0xvY2F0", + "b3JIYXNoZXMYASADKAsyDy5wcm90b3dpcmUuSGFzaCJiChZSZXF1ZXN0QW50", + "aWNvbmVNZXNzYWdlEiIKCWJsb2NrSGFzaBgBIAEoCzIPLnByb3Rvd2lyZS5I", + "YXNoEiQKC2NvbnRleHRIYXNoGAIgASgLMg8ucHJvdG93aXJlLkhhc2giSQoh", + "SWJkQmxvY2tMb2NhdG9ySGlnaGVzdEhhc2hNZXNzYWdlEiQKC2hpZ2hlc3RI", + "YXNoGAEgASgLMg8ucHJvdG93aXJlLkhhc2giKwopSWJkQmxvY2tMb2NhdG9y", + "SGlnaGVzdEhhc2hOb3RGb3VuZE1lc3NhZ2UiQwoTQmxvY2tIZWFkZXJzTWVz", + "c2FnZRIsCgxibG9ja0hlYWRlcnMYASADKAsyFi5wcm90b3dpcmUuQmxvY2tI", + "ZWFkZXIiKgooUmVxdWVzdFBydW5pbmdQb2ludEFuZEl0c0FudGljb25lTWVz", + "c2FnZSI0CjJSZXF1ZXN0TmV4dFBydW5pbmdQb2ludEFuZEl0c0FudGljb25l", + "QmxvY2tzTWVzc2FnZSK7AQobQmxvY2tXaXRoVHJ1c3RlZERhdGFNZXNzYWdl", + "EiYKBWJsb2NrGAEgASgLMhcucHJvdG93aXJlLkJsb2NrTWVzc2FnZRIQCghk", + "YWFTY29yZRgCIAEoBBImCglkYWFXaW5kb3cYAyADKAsyEy5wcm90b3dpcmUu", + "RGFhQmxvY2sSOgoMZ2hvc3RkYWdEYXRhGAQgAygLMiQucHJvdG93aXJlLkJs", + "b2NrR2hvc3RkYWdEYXRhSGFzaFBhaXIiYQoIRGFhQmxvY2sSJgoFYmxvY2sY", + "AyABKAsyFy5wcm90b3dpcmUuQmxvY2tNZXNzYWdlEi0KDGdob3N0ZGFnRGF0", + "YRgCIAEoCzIXLnByb3Rvd2lyZS5HaG9zdGRhZ0RhdGEiYwoKRGFhQmxvY2tW", + "NBImCgZoZWFkZXIYASABKAsyFi5wcm90b3dpcmUuQmxvY2tIZWFkZXISLQoM", + "Z2hvc3RkYWdEYXRhGAIgASgLMhcucHJvdG93aXJlLkdob3N0ZGFnRGF0YSJp", + "ChlCbG9ja0dob3N0ZGFnRGF0YUhhc2hQYWlyEh0KBGhhc2gYASABKAsyDy5w", + "cm90b3dpcmUuSGFzaBItCgxnaG9zdGRhZ0RhdGEYAiABKAsyFy5wcm90b3dp", + "cmUuR2hvc3RkYWdEYXRhIuYBCgxHaG9zdGRhZ0RhdGESEQoJYmx1ZVNjb3Jl", + "GAEgASgEEhAKCGJsdWVXb3JrGAIgASgMEicKDnNlbGVjdGVkUGFyZW50GAMg", + "ASgLMg8ucHJvdG93aXJlLkhhc2gSJgoNbWVyZ2VTZXRCbHVlcxgEIAMoCzIP", + "LnByb3Rvd2lyZS5IYXNoEiUKDG1lcmdlU2V0UmVkcxgFIAMoCzIPLnByb3Rv", + "d2lyZS5IYXNoEjkKEmJsdWVzQW50aWNvbmVTaXplcxgGIAMoCzIdLnByb3Rv", + "d2lyZS5CbHVlc0FudGljb25lU2l6ZXMiTQoSQmx1ZXNBbnRpY29uZVNpemVz", + "EiEKCGJsdWVIYXNoGAEgASgLMg8ucHJvdG93aXJlLkhhc2gSFAoMYW50aWNv", + "bmVTaXplGAIgASgNIiIKIERvbmVCbG9ja3NXaXRoVHJ1c3RlZERhdGFNZXNz", + "YWdlIj8KFFBydW5pbmdQb2ludHNNZXNzYWdlEicKB2hlYWRlcnMYASADKAsy", + "Fi5wcm90b3dpcmUuQmxvY2tIZWFkZXIiIQofUmVxdWVzdFBydW5pbmdQb2lu", + "dFByb29mTWVzc2FnZSJUChhQcnVuaW5nUG9pbnRQcm9vZk1lc3NhZ2USOAoH", + "aGVhZGVycxgBIAMoCzInLnByb3Rvd2lyZS5QcnVuaW5nUG9pbnRQcm9vZkhl", + "YWRlckFycmF5IkcKHFBydW5pbmdQb2ludFByb29mSGVhZGVyQXJyYXkSJwoH", + "aGVhZGVycxgBIAMoCzIWLnByb3Rvd2lyZS5CbG9ja0hlYWRlciIOCgxSZWFk", + "eU1lc3NhZ2UifgodQmxvY2tXaXRoVHJ1c3RlZERhdGFWNE1lc3NhZ2USJgoF", + "YmxvY2sYASABKAsyFy5wcm90b3dpcmUuQmxvY2tNZXNzYWdlEhgKEGRhYVdp", + "bmRvd0luZGljZXMYAiADKAQSGwoTZ2hvc3RkYWdEYXRhSW5kaWNlcxgDIAMo", + "BCJ6ChJUcnVzdGVkRGF0YU1lc3NhZ2USKAoJZGFhV2luZG93GAEgAygLMhUu", + "cHJvdG93aXJlLkRhYUJsb2NrVjQSOgoMZ2hvc3RkYWdEYXRhGAIgAygLMiQu", + "cHJvdG93aXJlLkJsb2NrR2hvc3RkYWdEYXRhSGFzaFBhaXJCJaoCIk1pbmlu", + "Z2NvcmUuQmxvY2tjaGFpbi5LYXNwYS5LYXNwYWRiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAddressesMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAddressesMessage.Parser, new[]{ "IncludeAllSubnetworks", "SubnetworkId" }, null, null, null, null), + 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.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), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey), global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey.Parser, new[]{ "Script", "Version" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionOutput), global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionOutput.Parser, new[]{ "Value", "ScriptPublicKey" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage.Parser, new[]{ "Header", "Transactions" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader.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.BlockLevelParents), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLevelParents.Parser, new[]{ "ParentHashes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.Hash), global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser, new[]{ "Bytes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestBlockLocatorMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestBlockLocatorMessage.Parser, new[]{ "HighHash", "Limit" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLocatorMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLocatorMessage.Parser, new[]{ "Hashes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestHeadersMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestHeadersMessage.Parser, new[]{ "LowHash", "HighHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextHeadersMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextHeadersMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.DoneHeadersMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.DoneHeadersMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestRelayBlocksMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestRelayBlocksMessage.Parser, new[]{ "Hashes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestTransactionsMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestTransactionsMessage.Parser, new[]{ "Ids" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionNotFoundMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionNotFoundMessage.Parser, new[]{ "Id" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.InvRelayBlockMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.InvRelayBlockMessage.Parser, new[]{ "Hash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.InvTransactionsMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.InvTransactionsMessage.Parser, new[]{ "Ids" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.PingMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.PingMessage.Parser, new[]{ "Nonce" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.PongMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.PongMessage.Parser, new[]{ "Nonce" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.VerackMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.VerackMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.VersionMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.VersionMessage.Parser, new[]{ "ProtocolVersion", "Services", "Timestamp", "Address", "Id", "UserAgent", "DisableRelayTx", "SubnetworkId", "Network" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RejectMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RejectMessage.Parser, new[]{ "Reason" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointUTXOSetMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointUTXOSetMessage.Parser, new[]{ "PruningPointHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUtxoSetChunkMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUtxoSetChunkMessage.Parser, new[]{ "OutpointAndUtxoEntryPairs" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.OutpointAndUtxoEntryPair), global::Miningcore.Blockchain.Kaspa.Kaspad.OutpointAndUtxoEntryPair.Parser, new[]{ "Outpoint", "UtxoEntry" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.UtxoEntry), global::Miningcore.Blockchain.Kaspa.Kaspad.UtxoEntry.Parser, new[]{ "Amount", "ScriptPublicKey", "BlockDaaScore", "IsCoinbase" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointUtxoSetChunkMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointUtxoSetChunkMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.DonePruningPointUtxoSetChunksMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.DonePruningPointUtxoSetChunksMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDBlocksMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDBlocksMessage.Parser, new[]{ "Hashes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.UnexpectedPruningPointMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.UnexpectedPruningPointMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorMessage.Parser, new[]{ "TargetHash", "BlockLocatorHashes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDChainBlockLocatorMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestIBDChainBlockLocatorMessage.Parser, new[]{ "LowHash", "HighHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.IbdChainBlockLocatorMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.IbdChainBlockLocatorMessage.Parser, new[]{ "BlockLocatorHashes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAnticoneMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestAnticoneMessage.Parser, new[]{ "BlockHash", "ContextHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashMessage.Parser, new[]{ "HighestHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashNotFoundMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.IbdBlockLocatorHighestHashNotFoundMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeadersMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeadersMessage.Parser, new[]{ "BlockHeaders" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointAndItsAnticoneMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointAndItsAnticoneMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointAndItsAnticoneBlocksMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestNextPruningPointAndItsAnticoneBlocksMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataMessage.Parser, new[]{ "Block", "DaaScore", "DaaWindow", "GhostdagData" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.DaaBlock), global::Miningcore.Blockchain.Kaspa.Kaspad.DaaBlock.Parser, new[]{ "Block", "GhostdagData" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.DaaBlockV4), global::Miningcore.Blockchain.Kaspa.Kaspad.DaaBlockV4.Parser, new[]{ "Header", "GhostdagData" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockGhostdagDataHashPair), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockGhostdagDataHashPair.Parser, new[]{ "Hash", "GhostdagData" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData), global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData.Parser, new[]{ "BlueScore", "BlueWork", "SelectedParent", "MergeSetBlues", "MergeSetReds", "BluesAnticoneSizes" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BluesAnticoneSizes), global::Miningcore.Blockchain.Kaspa.Kaspad.BluesAnticoneSizes.Parser, new[]{ "BlueHash", "AnticoneSize" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.DoneBlocksWithTrustedDataMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.DoneBlocksWithTrustedDataMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointsMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointsMessage.Parser, new[]{ "Headers" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointProofMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.RequestPruningPointProofMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofMessage.Parser, new[]{ "Headers" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofHeaderArray), global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofHeaderArray.Parser, new[]{ "Headers" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.ReadyMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.ReadyMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataV4Message), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockWithTrustedDataV4Message.Parser, new[]{ "Block", "DaaWindowIndices", "GhostdagDataIndices" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.TrustedDataMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.TrustedDataMessage.Parser, new[]{ "DaaWindow", "GhostdagData" }, null, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class RequestAddressesMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestAddressesMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestAddressesMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestAddressesMessage(RequestAddressesMessage other) : this() { + includeAllSubnetworks_ = other.includeAllSubnetworks_; + subnetworkId_ = other.subnetworkId_ != null ? other.subnetworkId_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestAddressesMessage Clone() { + return new RequestAddressesMessage(this); + } + + /// Field number for the "includeAllSubnetworks" field. + public const int IncludeAllSubnetworksFieldNumber = 1; + private bool includeAllSubnetworks_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeAllSubnetworks { + get { return includeAllSubnetworks_; } + set { + includeAllSubnetworks_ = value; + } + } + + /// Field number for the "subnetworkId" field. + public const int SubnetworkIdFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId subnetworkId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId SubnetworkId { + get { return subnetworkId_; } + set { + subnetworkId_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestAddressesMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestAddressesMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (IncludeAllSubnetworks != other.IncludeAllSubnetworks) return false; + if (!object.Equals(SubnetworkId, other.SubnetworkId)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (IncludeAllSubnetworks != false) hash ^= IncludeAllSubnetworks.GetHashCode(); + if (subnetworkId_ != null) hash ^= SubnetworkId.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 (IncludeAllSubnetworks != false) { + output.WriteRawTag(8); + output.WriteBool(IncludeAllSubnetworks); + } + if (subnetworkId_ != null) { + output.WriteRawTag(18); + output.WriteMessage(SubnetworkId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (IncludeAllSubnetworks != false) { + size += 1 + 1; + } + if (subnetworkId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SubnetworkId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestAddressesMessage other) { + if (other == null) { + return; + } + if (other.IncludeAllSubnetworks != false) { + IncludeAllSubnetworks = other.IncludeAllSubnetworks; + } + if (other.subnetworkId_ != null) { + if (subnetworkId_ == null) { + SubnetworkId = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId(); + } + SubnetworkId.MergeFrom(other.SubnetworkId); + } + _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 8: { + IncludeAllSubnetworks = input.ReadBool(); + break; + } + case 18: { + if (subnetworkId_ == null) { + SubnetworkId = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId(); + } + input.ReadMessage(SubnetworkId); + break; + } + } + } + } + + } + + public sealed partial class AddressesMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AddressesMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddressesMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddressesMessage(AddressesMessage other) : this() { + addressList_ = other.addressList_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddressesMessage Clone() { + return new AddressesMessage(this); + } + + /// Field number for the "addressList" field. + public const int AddressListFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addressList_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.NetAddress.Parser); + private readonly pbc::RepeatedField addressList_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AddressList { + get { return addressList_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AddressesMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AddressesMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addressList_.Equals(other.addressList_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addressList_.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) { + addressList_.WriteTo(output, _repeated_addressList_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addressList_.CalculateSize(_repeated_addressList_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AddressesMessage other) { + if (other == null) { + return; + } + addressList_.Add(other.addressList_); + _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: { + addressList_.AddEntriesFrom(input, _repeated_addressList_codec); + break; + } + } + } + } + + } + + public sealed partial class NetAddress : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NetAddress()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddress() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddress(NetAddress other) : this() { + timestamp_ = other.timestamp_; + ip_ = other.ip_; + port_ = other.port_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NetAddress Clone() { + return new NetAddress(this); + } + + /// Field number for the "timestamp" field. + public const int TimestampFieldNumber = 1; + private long timestamp_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Timestamp { + get { return timestamp_; } + set { + timestamp_ = value; + } + } + + /// Field number for the "ip" field. + public const int IpFieldNumber = 3; + private pb::ByteString ip_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Ip { + get { return ip_; } + set { + ip_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "port" field. + public const int PortFieldNumber = 4; + private uint port_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Port { + get { return port_; } + set { + port_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NetAddress); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NetAddress other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Timestamp != other.Timestamp) return false; + if (Ip != other.Ip) return false; + if (Port != other.Port) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Timestamp != 0L) hash ^= Timestamp.GetHashCode(); + if (Ip.Length != 0) hash ^= Ip.GetHashCode(); + if (Port != 0) hash ^= Port.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 (Timestamp != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Timestamp); + } + if (Ip.Length != 0) { + output.WriteRawTag(26); + output.WriteBytes(Ip); + } + if (Port != 0) { + output.WriteRawTag(32); + output.WriteUInt32(Port); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Timestamp != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Timestamp); + } + if (Ip.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Ip); + } + if (Port != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Port); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NetAddress other) { + if (other == null) { + return; + } + if (other.Timestamp != 0L) { + Timestamp = other.Timestamp; + } + if (other.Ip.Length != 0) { + Ip = other.Ip; + } + if (other.Port != 0) { + Port = other.Port; + } + _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 8: { + Timestamp = input.ReadInt64(); + break; + } + case 26: { + Ip = input.ReadBytes(); + break; + } + case 32: { + Port = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class SubnetworkId : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SubnetworkId()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubnetworkId() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubnetworkId(SubnetworkId other) : this() { + bytes_ = other.bytes_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubnetworkId Clone() { + return new SubnetworkId(this); + } + + /// Field number for the "bytes" field. + public const int BytesFieldNumber = 1; + private pb::ByteString bytes_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Bytes { + get { return bytes_; } + set { + bytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SubnetworkId); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SubnetworkId other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Bytes != other.Bytes) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Bytes.Length != 0) hash ^= Bytes.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 (Bytes.Length != 0) { + output.WriteRawTag(10); + output.WriteBytes(Bytes); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Bytes.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Bytes); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SubnetworkId other) { + if (other == null) { + return; + } + if (other.Bytes.Length != 0) { + Bytes = other.Bytes; + } + _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: { + Bytes = input.ReadBytes(); + break; + } + } + } + } + + } + + public sealed partial class TransactionMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TransactionMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionMessage(TransactionMessage other) : this() { + version_ = other.version_; + inputs_ = other.inputs_.Clone(); + outputs_ = other.outputs_.Clone(); + lockTime_ = other.lockTime_; + subnetworkId_ = other.subnetworkId_ != null ? other.subnetworkId_.Clone() : null; + gas_ = other.gas_; + payload_ = other.payload_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionMessage Clone() { + return new TransactionMessage(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private uint version_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Version { + get { return version_; } + set { + version_ = value; + } + } + + /// Field number for the "inputs" field. + public const int InputsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_inputs_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionInput.Parser); + private readonly pbc::RepeatedField inputs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Inputs { + get { return inputs_; } + } + + /// Field number for the "outputs" field. + public const int OutputsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_outputs_codec + = pb::FieldCodec.ForMessage(26, global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionOutput.Parser); + private readonly pbc::RepeatedField outputs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Outputs { + get { return outputs_; } + } + + /// Field number for the "lockTime" field. + public const int LockTimeFieldNumber = 4; + private ulong lockTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong LockTime { + get { return lockTime_; } + set { + lockTime_ = value; + } + } + + /// Field number for the "subnetworkId" field. + public const int SubnetworkIdFieldNumber = 5; + private global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId subnetworkId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId SubnetworkId { + get { return subnetworkId_; } + set { + subnetworkId_ = value; + } + } + + /// Field number for the "gas" field. + public const int GasFieldNumber = 6; + private ulong gas_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Gas { + get { return gas_; } + set { + gas_ = value; + } + } + + /// Field number for the "payload" field. + public const int PayloadFieldNumber = 8; + private pb::ByteString payload_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Payload { + get { return payload_; } + set { + payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TransactionMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TransactionMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + if(!inputs_.Equals(other.inputs_)) return false; + if(!outputs_.Equals(other.outputs_)) return false; + if (LockTime != other.LockTime) return false; + if (!object.Equals(SubnetworkId, other.SubnetworkId)) return false; + if (Gas != other.Gas) return false; + if (Payload != other.Payload) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version != 0) hash ^= Version.GetHashCode(); + hash ^= inputs_.GetHashCode(); + hash ^= outputs_.GetHashCode(); + if (LockTime != 0UL) hash ^= LockTime.GetHashCode(); + if (subnetworkId_ != null) hash ^= SubnetworkId.GetHashCode(); + if (Gas != 0UL) hash ^= Gas.GetHashCode(); + if (Payload.Length != 0) hash ^= Payload.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 != 0) { + output.WriteRawTag(8); + output.WriteUInt32(Version); + } + inputs_.WriteTo(output, _repeated_inputs_codec); + outputs_.WriteTo(output, _repeated_outputs_codec); + if (LockTime != 0UL) { + output.WriteRawTag(32); + output.WriteUInt64(LockTime); + } + if (subnetworkId_ != null) { + output.WriteRawTag(42); + output.WriteMessage(SubnetworkId); + } + if (Gas != 0UL) { + output.WriteRawTag(48); + output.WriteUInt64(Gas); + } + if (Payload.Length != 0) { + output.WriteRawTag(66); + output.WriteBytes(Payload); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Version); + } + size += inputs_.CalculateSize(_repeated_inputs_codec); + size += outputs_.CalculateSize(_repeated_outputs_codec); + if (LockTime != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(LockTime); + } + if (subnetworkId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SubnetworkId); + } + if (Gas != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Gas); + } + if (Payload.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Payload); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TransactionMessage other) { + if (other == null) { + return; + } + if (other.Version != 0) { + Version = other.Version; + } + inputs_.Add(other.inputs_); + outputs_.Add(other.outputs_); + if (other.LockTime != 0UL) { + LockTime = other.LockTime; + } + if (other.subnetworkId_ != null) { + if (subnetworkId_ == null) { + SubnetworkId = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId(); + } + SubnetworkId.MergeFrom(other.SubnetworkId); + } + if (other.Gas != 0UL) { + Gas = other.Gas; + } + if (other.Payload.Length != 0) { + Payload = other.Payload; + } + _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 8: { + Version = input.ReadUInt32(); + break; + } + case 18: { + inputs_.AddEntriesFrom(input, _repeated_inputs_codec); + break; + } + case 26: { + outputs_.AddEntriesFrom(input, _repeated_outputs_codec); + break; + } + case 32: { + LockTime = input.ReadUInt64(); + break; + } + case 42: { + if (subnetworkId_ == null) { + SubnetworkId = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId(); + } + input.ReadMessage(SubnetworkId); + break; + } + case 48: { + Gas = input.ReadUInt64(); + break; + } + case 66: { + Payload = input.ReadBytes(); + break; + } + } + } + } + + } + + public sealed partial class TransactionInput : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TransactionInput()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionInput() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionInput(TransactionInput other) : this() { + previousOutpoint_ = other.previousOutpoint_ != null ? other.previousOutpoint_.Clone() : null; + signatureScript_ = other.signatureScript_; + sequence_ = other.sequence_; + sigOpCount_ = other.sigOpCount_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionInput Clone() { + return new TransactionInput(this); + } + + /// Field number for the "previousOutpoint" field. + public const int PreviousOutpointFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint previousOutpoint_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint PreviousOutpoint { + get { return previousOutpoint_; } + set { + previousOutpoint_ = value; + } + } + + /// Field number for the "signatureScript" field. + public const int SignatureScriptFieldNumber = 2; + private pb::ByteString signatureScript_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString SignatureScript { + get { return signatureScript_; } + set { + signatureScript_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "sequence" field. + public const int SequenceFieldNumber = 3; + private ulong sequence_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Sequence { + get { return sequence_; } + set { + sequence_ = value; + } + } + + /// Field number for the "sigOpCount" field. + public const int SigOpCountFieldNumber = 4; + private uint sigOpCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint SigOpCount { + get { return sigOpCount_; } + set { + sigOpCount_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TransactionInput); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TransactionInput other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(PreviousOutpoint, other.PreviousOutpoint)) return false; + if (SignatureScript != other.SignatureScript) return false; + if (Sequence != other.Sequence) return false; + if (SigOpCount != other.SigOpCount) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (previousOutpoint_ != null) hash ^= PreviousOutpoint.GetHashCode(); + if (SignatureScript.Length != 0) hash ^= SignatureScript.GetHashCode(); + if (Sequence != 0UL) hash ^= Sequence.GetHashCode(); + if (SigOpCount != 0) hash ^= SigOpCount.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 (previousOutpoint_ != null) { + output.WriteRawTag(10); + output.WriteMessage(PreviousOutpoint); + } + if (SignatureScript.Length != 0) { + output.WriteRawTag(18); + output.WriteBytes(SignatureScript); + } + if (Sequence != 0UL) { + output.WriteRawTag(24); + output.WriteUInt64(Sequence); + } + if (SigOpCount != 0) { + output.WriteRawTag(32); + output.WriteUInt32(SigOpCount); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (previousOutpoint_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PreviousOutpoint); + } + if (SignatureScript.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(SignatureScript); + } + if (Sequence != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Sequence); + } + if (SigOpCount != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(SigOpCount); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TransactionInput other) { + if (other == null) { + return; + } + if (other.previousOutpoint_ != null) { + if (previousOutpoint_ == null) { + PreviousOutpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint(); + } + PreviousOutpoint.MergeFrom(other.PreviousOutpoint); + } + if (other.SignatureScript.Length != 0) { + SignatureScript = other.SignatureScript; + } + if (other.Sequence != 0UL) { + Sequence = other.Sequence; + } + if (other.SigOpCount != 0) { + SigOpCount = other.SigOpCount; + } + _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: { + if (previousOutpoint_ == null) { + PreviousOutpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint(); + } + input.ReadMessage(PreviousOutpoint); + break; + } + case 18: { + SignatureScript = input.ReadBytes(); + break; + } + case 24: { + Sequence = input.ReadUInt64(); + break; + } + case 32: { + SigOpCount = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class Outpoint : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Outpoint()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Outpoint() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Outpoint(Outpoint other) : this() { + transactionId_ = other.transactionId_ != null ? other.transactionId_.Clone() : null; + index_ = other.index_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Outpoint Clone() { + return new Outpoint(this); + } + + /// Field number for the "transactionId" field. + public const int TransactionIdFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId transactionId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId TransactionId { + get { return transactionId_; } + set { + transactionId_ = value; + } + } + + /// Field number for the "index" field. + public const int IndexFieldNumber = 2; + private uint index_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Index { + get { return index_; } + set { + index_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Outpoint); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Outpoint other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(TransactionId, other.TransactionId)) return false; + if (Index != other.Index) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (transactionId_ != null) hash ^= TransactionId.GetHashCode(); + if (Index != 0) hash ^= Index.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 (transactionId_ != null) { + output.WriteRawTag(10); + output.WriteMessage(TransactionId); + } + if (Index != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Index); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (transactionId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(TransactionId); + } + if (Index != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Index); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Outpoint other) { + if (other == null) { + return; + } + if (other.transactionId_ != null) { + if (transactionId_ == null) { + TransactionId = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId(); + } + TransactionId.MergeFrom(other.TransactionId); + } + if (other.Index != 0) { + Index = other.Index; + } + _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: { + if (transactionId_ == null) { + TransactionId = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId(); + } + input.ReadMessage(TransactionId); + break; + } + case 16: { + Index = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class TransactionId : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TransactionId()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionId() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionId(TransactionId other) : this() { + bytes_ = other.bytes_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionId Clone() { + return new TransactionId(this); + } + + /// Field number for the "bytes" field. + public const int BytesFieldNumber = 1; + private pb::ByteString bytes_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Bytes { + get { return bytes_; } + set { + bytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TransactionId); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TransactionId other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Bytes != other.Bytes) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Bytes.Length != 0) hash ^= Bytes.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 (Bytes.Length != 0) { + output.WriteRawTag(10); + output.WriteBytes(Bytes); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Bytes.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Bytes); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TransactionId other) { + if (other == null) { + return; + } + if (other.Bytes.Length != 0) { + Bytes = other.Bytes; + } + _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: { + Bytes = input.ReadBytes(); + break; + } + } + } + } + + } + + public sealed partial class ScriptPublicKey : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ScriptPublicKey()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ScriptPublicKey() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ScriptPublicKey(ScriptPublicKey other) : this() { + script_ = other.script_; + version_ = other.version_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ScriptPublicKey Clone() { + return new ScriptPublicKey(this); + } + + /// Field number for the "script" field. + public const int ScriptFieldNumber = 1; + private pb::ByteString script_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Script { + get { return script_; } + set { + script_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 2; + private uint version_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Version { + get { return version_; } + set { + version_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ScriptPublicKey); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ScriptPublicKey other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Script != other.Script) return false; + if (Version != other.Version) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Script.Length != 0) hash ^= Script.GetHashCode(); + if (Version != 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 (Script.Length != 0) { + output.WriteRawTag(10); + output.WriteBytes(Script); + } + if (Version != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Version); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Script.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Script); + } + if (Version != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Version); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ScriptPublicKey other) { + if (other == null) { + return; + } + if (other.Script.Length != 0) { + Script = other.Script; + } + if (other.Version != 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: { + Script = input.ReadBytes(); + break; + } + case 16: { + Version = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class TransactionOutput : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TransactionOutput()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionOutput() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionOutput(TransactionOutput other) : this() { + value_ = other.value_; + scriptPublicKey_ = other.scriptPublicKey_ != null ? other.scriptPublicKey_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionOutput Clone() { + return new TransactionOutput(this); + } + + /// Field number for the "value" field. + public const int ValueFieldNumber = 1; + private ulong value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Value { + get { return value_; } + set { + value_ = value; + } + } + + /// Field number for the "scriptPublicKey" field. + public const int ScriptPublicKeyFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey scriptPublicKey_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey ScriptPublicKey { + get { return scriptPublicKey_; } + set { + scriptPublicKey_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TransactionOutput); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TransactionOutput other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Value != other.Value) return false; + if (!object.Equals(ScriptPublicKey, other.ScriptPublicKey)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Value != 0UL) hash ^= Value.GetHashCode(); + if (scriptPublicKey_ != null) hash ^= ScriptPublicKey.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 (Value != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Value); + } + if (scriptPublicKey_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ScriptPublicKey); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Value != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Value); + } + if (scriptPublicKey_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ScriptPublicKey); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TransactionOutput other) { + if (other == null) { + return; + } + if (other.Value != 0UL) { + Value = other.Value; + } + if (other.scriptPublicKey_ != null) { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey(); + } + ScriptPublicKey.MergeFrom(other.ScriptPublicKey); + } + _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 8: { + Value = input.ReadUInt64(); + break; + } + case 18: { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey(); + } + input.ReadMessage(ScriptPublicKey); + break; + } + } + } + } + + } + + public sealed partial class BlockMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockMessage(BlockMessage other) : this() { + header_ = other.header_ != null ? other.header_.Clone() : null; + transactions_ = other.transactions_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockMessage Clone() { + return new BlockMessage(this); + } + + /// Field number for the "header" field. + public const int HeaderFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader header_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader Header { + get { return header_; } + set { + header_ = value; + } + } + + /// Field number for the "transactions" field. + public const int TransactionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_transactions_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionMessage.Parser); + private readonly pbc::RepeatedField transactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Transactions { + get { return transactions_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Header, other.Header)) return false; + if(!transactions_.Equals(other.transactions_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (header_ != null) hash ^= Header.GetHashCode(); + hash ^= transactions_.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 (header_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Header); + } + transactions_.WriteTo(output, _repeated_transactions_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (header_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Header); + } + size += transactions_.CalculateSize(_repeated_transactions_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockMessage other) { + if (other == null) { + return; + } + if (other.header_ != null) { + if (header_ == null) { + Header = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader(); + } + Header.MergeFrom(other.Header); + } + transactions_.Add(other.transactions_); + _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: { + if (header_ == null) { + Header = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader(); + } + input.ReadMessage(Header); + break; + } + case 18: { + transactions_.AddEntriesFrom(input, _repeated_transactions_codec); + break; + } + } + } + } + + } + + public sealed partial class BlockHeader : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockHeader()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[11]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockHeader() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockHeader(BlockHeader other) : this() { + version_ = other.version_; + parents_ = other.parents_.Clone(); + hashMerkleRoot_ = other.hashMerkleRoot_ != null ? other.hashMerkleRoot_.Clone() : null; + acceptedIdMerkleRoot_ = other.acceptedIdMerkleRoot_ != null ? other.acceptedIdMerkleRoot_.Clone() : null; + utxoCommitment_ = other.utxoCommitment_ != null ? other.utxoCommitment_.Clone() : null; + timestamp_ = other.timestamp_; + bits_ = other.bits_; + nonce_ = other.nonce_; + daaScore_ = other.daaScore_; + blueWork_ = other.blueWork_; + pruningPoint_ = other.pruningPoint_ != null ? other.pruningPoint_.Clone() : null; + blueScore_ = other.blueScore_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockHeader Clone() { + return new BlockHeader(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private uint version_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Version { + get { return version_; } + set { + version_ = value; + } + } + + /// Field number for the "parents" field. + public const int ParentsFieldNumber = 12; + private static readonly pb::FieldCodec _repeated_parents_codec + = pb::FieldCodec.ForMessage(98, global::Miningcore.Blockchain.Kaspa.Kaspad.BlockLevelParents.Parser); + private readonly pbc::RepeatedField parents_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Parents { + get { return parents_; } + } + + /// Field number for the "hashMerkleRoot" field. + public const int HashMerkleRootFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash hashMerkleRoot_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash HashMerkleRoot { + get { return hashMerkleRoot_; } + set { + hashMerkleRoot_ = value; + } + } + + /// Field number for the "acceptedIdMerkleRoot" field. + public const int AcceptedIdMerkleRootFieldNumber = 4; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash acceptedIdMerkleRoot_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash AcceptedIdMerkleRoot { + get { return acceptedIdMerkleRoot_; } + set { + acceptedIdMerkleRoot_ = value; + } + } + + /// Field number for the "utxoCommitment" field. + public const int UtxoCommitmentFieldNumber = 5; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash utxoCommitment_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash UtxoCommitment { + get { return utxoCommitment_; } + set { + utxoCommitment_ = value; + } + } + + /// Field number for the "timestamp" field. + public const int TimestampFieldNumber = 6; + private long timestamp_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Timestamp { + get { return timestamp_; } + set { + timestamp_ = value; + } + } + + /// Field number for the "bits" field. + public const int BitsFieldNumber = 7; + private uint bits_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Bits { + get { return bits_; } + set { + bits_ = value; + } + } + + /// Field number for the "nonce" field. + public const int NonceFieldNumber = 8; + private ulong nonce_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Nonce { + get { return nonce_; } + set { + nonce_ = value; + } + } + + /// Field number for the "daaScore" field. + public const int DaaScoreFieldNumber = 9; + private ulong daaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong DaaScore { + get { return daaScore_; } + set { + daaScore_ = value; + } + } + + /// Field number for the "blueWork" field. + public const int BlueWorkFieldNumber = 10; + private pb::ByteString blueWork_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString BlueWork { + get { return blueWork_; } + set { + blueWork_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "pruningPoint" field. + public const int PruningPointFieldNumber = 14; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash pruningPoint_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash PruningPoint { + get { return pruningPoint_; } + set { + pruningPoint_ = value; + } + } + + /// Field number for the "blueScore" field. + public const int BlueScoreFieldNumber = 13; + private ulong blueScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlueScore { + get { return blueScore_; } + set { + blueScore_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockHeader); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockHeader other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + if(!parents_.Equals(other.parents_)) return false; + if (!object.Equals(HashMerkleRoot, other.HashMerkleRoot)) return false; + if (!object.Equals(AcceptedIdMerkleRoot, other.AcceptedIdMerkleRoot)) return false; + if (!object.Equals(UtxoCommitment, other.UtxoCommitment)) return false; + if (Timestamp != other.Timestamp) return false; + if (Bits != other.Bits) return false; + if (Nonce != other.Nonce) return false; + if (DaaScore != other.DaaScore) return false; + if (BlueWork != other.BlueWork) return false; + if (!object.Equals(PruningPoint, other.PruningPoint)) return false; + if (BlueScore != other.BlueScore) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version != 0) hash ^= Version.GetHashCode(); + hash ^= parents_.GetHashCode(); + if (hashMerkleRoot_ != null) hash ^= HashMerkleRoot.GetHashCode(); + if (acceptedIdMerkleRoot_ != null) hash ^= AcceptedIdMerkleRoot.GetHashCode(); + if (utxoCommitment_ != null) hash ^= UtxoCommitment.GetHashCode(); + if (Timestamp != 0L) hash ^= Timestamp.GetHashCode(); + if (Bits != 0) hash ^= Bits.GetHashCode(); + if (Nonce != 0UL) hash ^= Nonce.GetHashCode(); + if (DaaScore != 0UL) hash ^= DaaScore.GetHashCode(); + if (BlueWork.Length != 0) hash ^= BlueWork.GetHashCode(); + if (pruningPoint_ != null) hash ^= PruningPoint.GetHashCode(); + if (BlueScore != 0UL) hash ^= BlueScore.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 != 0) { + output.WriteRawTag(8); + output.WriteUInt32(Version); + } + if (hashMerkleRoot_ != null) { + output.WriteRawTag(26); + output.WriteMessage(HashMerkleRoot); + } + if (acceptedIdMerkleRoot_ != null) { + output.WriteRawTag(34); + output.WriteMessage(AcceptedIdMerkleRoot); + } + if (utxoCommitment_ != null) { + output.WriteRawTag(42); + output.WriteMessage(UtxoCommitment); + } + if (Timestamp != 0L) { + output.WriteRawTag(48); + output.WriteInt64(Timestamp); + } + if (Bits != 0) { + output.WriteRawTag(56); + output.WriteUInt32(Bits); + } + if (Nonce != 0UL) { + output.WriteRawTag(64); + output.WriteUInt64(Nonce); + } + if (DaaScore != 0UL) { + output.WriteRawTag(72); + output.WriteUInt64(DaaScore); + } + if (BlueWork.Length != 0) { + output.WriteRawTag(82); + output.WriteBytes(BlueWork); + } + parents_.WriteTo(output, _repeated_parents_codec); + if (BlueScore != 0UL) { + output.WriteRawTag(104); + output.WriteUInt64(BlueScore); + } + if (pruningPoint_ != null) { + output.WriteRawTag(114); + output.WriteMessage(PruningPoint); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Version); + } + size += parents_.CalculateSize(_repeated_parents_codec); + if (hashMerkleRoot_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(HashMerkleRoot); + } + if (acceptedIdMerkleRoot_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(AcceptedIdMerkleRoot); + } + if (utxoCommitment_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(UtxoCommitment); + } + if (Timestamp != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Timestamp); + } + if (Bits != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Bits); + } + if (Nonce != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Nonce); + } + if (DaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(DaaScore); + } + if (BlueWork.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(BlueWork); + } + if (pruningPoint_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PruningPoint); + } + if (BlueScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlueScore); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockHeader other) { + if (other == null) { + return; + } + if (other.Version != 0) { + Version = other.Version; + } + parents_.Add(other.parents_); + if (other.hashMerkleRoot_ != null) { + if (hashMerkleRoot_ == null) { + HashMerkleRoot = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + HashMerkleRoot.MergeFrom(other.HashMerkleRoot); + } + if (other.acceptedIdMerkleRoot_ != null) { + if (acceptedIdMerkleRoot_ == null) { + AcceptedIdMerkleRoot = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + AcceptedIdMerkleRoot.MergeFrom(other.AcceptedIdMerkleRoot); + } + if (other.utxoCommitment_ != null) { + if (utxoCommitment_ == null) { + UtxoCommitment = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + UtxoCommitment.MergeFrom(other.UtxoCommitment); + } + if (other.Timestamp != 0L) { + Timestamp = other.Timestamp; + } + if (other.Bits != 0) { + Bits = other.Bits; + } + if (other.Nonce != 0UL) { + Nonce = other.Nonce; + } + if (other.DaaScore != 0UL) { + DaaScore = other.DaaScore; + } + if (other.BlueWork.Length != 0) { + BlueWork = other.BlueWork; + } + if (other.pruningPoint_ != null) { + if (pruningPoint_ == null) { + PruningPoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + PruningPoint.MergeFrom(other.PruningPoint); + } + if (other.BlueScore != 0UL) { + BlueScore = other.BlueScore; + } + _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 8: { + Version = input.ReadUInt32(); + break; + } + case 26: { + if (hashMerkleRoot_ == null) { + HashMerkleRoot = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(HashMerkleRoot); + break; + } + case 34: { + if (acceptedIdMerkleRoot_ == null) { + AcceptedIdMerkleRoot = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(AcceptedIdMerkleRoot); + break; + } + case 42: { + if (utxoCommitment_ == null) { + UtxoCommitment = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(UtxoCommitment); + break; + } + case 48: { + Timestamp = input.ReadInt64(); + break; + } + case 56: { + Bits = input.ReadUInt32(); + break; + } + case 64: { + Nonce = input.ReadUInt64(); + break; + } + case 72: { + DaaScore = input.ReadUInt64(); + break; + } + case 82: { + BlueWork = input.ReadBytes(); + break; + } + case 98: { + parents_.AddEntriesFrom(input, _repeated_parents_codec); + break; + } + case 104: { + BlueScore = input.ReadUInt64(); + break; + } + case 114: { + if (pruningPoint_ == null) { + PruningPoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(PruningPoint); + break; + } + } + } + } + + } + + public sealed partial class BlockLevelParents : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockLevelParents()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockLevelParents() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockLevelParents(BlockLevelParents other) : this() { + parentHashes_ = other.parentHashes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockLevelParents Clone() { + return new BlockLevelParents(this); + } + + /// Field number for the "parentHashes" field. + public const int ParentHashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_parentHashes_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField parentHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField ParentHashes { + get { return parentHashes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockLevelParents); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockLevelParents other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!parentHashes_.Equals(other.parentHashes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= parentHashes_.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) { + parentHashes_.WriteTo(output, _repeated_parentHashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += parentHashes_.CalculateSize(_repeated_parentHashes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockLevelParents other) { + if (other == null) { + return; + } + parentHashes_.Add(other.parentHashes_); + _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: { + parentHashes_.AddEntriesFrom(input, _repeated_parentHashes_codec); + break; + } + } + } + } + + } + + public sealed partial class Hash : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Hash()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Hash() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Hash(Hash other) : this() { + bytes_ = other.bytes_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public Hash Clone() { + return new Hash(this); + } + + /// Field number for the "bytes" field. + public const int BytesFieldNumber = 1; + private pb::ByteString bytes_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Bytes { + get { return bytes_; } + set { + bytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as Hash); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(Hash other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Bytes != other.Bytes) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Bytes.Length != 0) hash ^= Bytes.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 (Bytes.Length != 0) { + output.WriteRawTag(10); + output.WriteBytes(Bytes); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Bytes.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Bytes); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(Hash other) { + if (other == null) { + return; + } + if (other.Bytes.Length != 0) { + Bytes = other.Bytes; + } + _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: { + Bytes = input.ReadBytes(); + break; + } + } + } + } + + } + + public sealed partial class RequestBlockLocatorMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestBlockLocatorMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[14]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestBlockLocatorMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestBlockLocatorMessage(RequestBlockLocatorMessage other) : this() { + highHash_ = other.highHash_ != null ? other.highHash_.Clone() : null; + limit_ = other.limit_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestBlockLocatorMessage Clone() { + return new RequestBlockLocatorMessage(this); + } + + /// Field number for the "highHash" field. + public const int HighHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash highHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash HighHash { + get { return highHash_; } + set { + highHash_ = value; + } + } + + /// Field number for the "limit" field. + public const int LimitFieldNumber = 2; + private uint limit_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Limit { + get { return limit_; } + set { + limit_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestBlockLocatorMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestBlockLocatorMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(HighHash, other.HighHash)) return false; + if (Limit != other.Limit) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (highHash_ != null) hash ^= HighHash.GetHashCode(); + if (Limit != 0) hash ^= Limit.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 (highHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(HighHash); + } + if (Limit != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Limit); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (highHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(HighHash); + } + if (Limit != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Limit); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestBlockLocatorMessage other) { + if (other == null) { + return; + } + if (other.highHash_ != null) { + if (highHash_ == null) { + HighHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + HighHash.MergeFrom(other.HighHash); + } + if (other.Limit != 0) { + Limit = other.Limit; + } + _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: { + if (highHash_ == null) { + HighHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(HighHash); + break; + } + case 16: { + Limit = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class BlockLocatorMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockLocatorMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[15]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockLocatorMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockLocatorMessage(BlockLocatorMessage other) : this() { + hashes_ = other.hashes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockLocatorMessage Clone() { + return new BlockLocatorMessage(this); + } + + /// Field number for the "hashes" field. + public const int HashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_hashes_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField hashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Hashes { + get { return hashes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockLocatorMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockLocatorMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!hashes_.Equals(other.hashes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= hashes_.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) { + hashes_.WriteTo(output, _repeated_hashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += hashes_.CalculateSize(_repeated_hashes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockLocatorMessage other) { + if (other == null) { + return; + } + hashes_.Add(other.hashes_); + _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: { + hashes_.AddEntriesFrom(input, _repeated_hashes_codec); + break; + } + } + } + } + + } + + public sealed partial class RequestHeadersMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestHeadersMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[16]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestHeadersMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestHeadersMessage(RequestHeadersMessage other) : this() { + lowHash_ = other.lowHash_ != null ? other.lowHash_.Clone() : null; + highHash_ = other.highHash_ != null ? other.highHash_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestHeadersMessage Clone() { + return new RequestHeadersMessage(this); + } + + /// Field number for the "lowHash" field. + public const int LowHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash lowHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash LowHash { + get { return lowHash_; } + set { + lowHash_ = value; + } + } + + /// Field number for the "highHash" field. + public const int HighHashFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash highHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash HighHash { + get { return highHash_; } + set { + highHash_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestHeadersMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestHeadersMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(LowHash, other.LowHash)) return false; + if (!object.Equals(HighHash, other.HighHash)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (lowHash_ != null) hash ^= LowHash.GetHashCode(); + if (highHash_ != null) hash ^= HighHash.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 (lowHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(LowHash); + } + if (highHash_ != null) { + output.WriteRawTag(18); + output.WriteMessage(HighHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (lowHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(LowHash); + } + if (highHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(HighHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestHeadersMessage other) { + if (other == null) { + return; + } + if (other.lowHash_ != null) { + if (lowHash_ == null) { + LowHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + LowHash.MergeFrom(other.LowHash); + } + if (other.highHash_ != null) { + if (highHash_ == null) { + HighHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + HighHash.MergeFrom(other.HighHash); + } + _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: { + if (lowHash_ == null) { + LowHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(LowHash); + break; + } + case 18: { + if (highHash_ == null) { + HighHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(HighHash); + break; + } + } + } + } + + } + + public sealed partial class RequestNextHeadersMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestNextHeadersMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[17]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextHeadersMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextHeadersMessage(RequestNextHeadersMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextHeadersMessage Clone() { + return new RequestNextHeadersMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestNextHeadersMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestNextHeadersMessage 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(RequestNextHeadersMessage 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 DoneHeadersMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DoneHeadersMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[18]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DoneHeadersMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DoneHeadersMessage(DoneHeadersMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DoneHeadersMessage Clone() { + return new DoneHeadersMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DoneHeadersMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DoneHeadersMessage 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(DoneHeadersMessage 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 RequestRelayBlocksMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestRelayBlocksMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[19]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestRelayBlocksMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestRelayBlocksMessage(RequestRelayBlocksMessage other) : this() { + hashes_ = other.hashes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestRelayBlocksMessage Clone() { + return new RequestRelayBlocksMessage(this); + } + + /// Field number for the "hashes" field. + public const int HashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_hashes_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField hashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Hashes { + get { return hashes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestRelayBlocksMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestRelayBlocksMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!hashes_.Equals(other.hashes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= hashes_.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) { + hashes_.WriteTo(output, _repeated_hashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += hashes_.CalculateSize(_repeated_hashes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestRelayBlocksMessage other) { + if (other == null) { + return; + } + hashes_.Add(other.hashes_); + _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: { + hashes_.AddEntriesFrom(input, _repeated_hashes_codec); + break; + } + } + } + } + + } + + public sealed partial class RequestTransactionsMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestTransactionsMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[20]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestTransactionsMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestTransactionsMessage(RequestTransactionsMessage other) : this() { + ids_ = other.ids_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestTransactionsMessage Clone() { + return new RequestTransactionsMessage(this); + } + + /// Field number for the "ids" field. + public const int IdsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_ids_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId.Parser); + private readonly pbc::RepeatedField ids_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ids { + get { return ids_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestTransactionsMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestTransactionsMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!ids_.Equals(other.ids_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= ids_.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) { + ids_.WriteTo(output, _repeated_ids_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += ids_.CalculateSize(_repeated_ids_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestTransactionsMessage other) { + if (other == null) { + return; + } + ids_.Add(other.ids_); + _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: { + ids_.AddEntriesFrom(input, _repeated_ids_codec); + break; + } + } + } + } + + } + + public sealed partial class TransactionNotFoundMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TransactionNotFoundMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[21]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionNotFoundMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionNotFoundMessage(TransactionNotFoundMessage other) : this() { + id_ = other.id_ != null ? other.id_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TransactionNotFoundMessage Clone() { + return new TransactionNotFoundMessage(this); + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId Id { + get { return id_; } + set { + id_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TransactionNotFoundMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TransactionNotFoundMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Id, other.Id)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (id_ != null) hash ^= Id.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 (id_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Id); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (id_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Id); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TransactionNotFoundMessage other) { + if (other == null) { + return; + } + if (other.id_ != null) { + if (id_ == null) { + Id = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId(); + } + Id.MergeFrom(other.Id); + } + _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: { + if (id_ == null) { + Id = new global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId(); + } + input.ReadMessage(Id); + break; + } + } + } + } + + } + + public sealed partial class InvRelayBlockMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new InvRelayBlockMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[22]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public InvRelayBlockMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public InvRelayBlockMessage(InvRelayBlockMessage other) : this() { + hash_ = other.hash_ != null ? other.hash_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public InvRelayBlockMessage Clone() { + return new InvRelayBlockMessage(this); + } + + /// Field number for the "hash" field. + public const int HashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash hash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash Hash { + get { return hash_; } + set { + hash_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as InvRelayBlockMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(InvRelayBlockMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Hash, other.Hash)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (hash_ != null) hash ^= Hash.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 (hash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Hash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (hash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Hash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(InvRelayBlockMessage other) { + if (other == null) { + return; + } + if (other.hash_ != null) { + if (hash_ == null) { + Hash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + Hash.MergeFrom(other.Hash); + } + _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: { + if (hash_ == null) { + Hash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(Hash); + break; + } + } + } + } + + } + + public sealed partial class InvTransactionsMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new InvTransactionsMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[23]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public InvTransactionsMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public InvTransactionsMessage(InvTransactionsMessage other) : this() { + ids_ = other.ids_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public InvTransactionsMessage Clone() { + return new InvTransactionsMessage(this); + } + + /// Field number for the "ids" field. + public const int IdsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_ids_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.TransactionId.Parser); + private readonly pbc::RepeatedField ids_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Ids { + get { return ids_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as InvTransactionsMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(InvTransactionsMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!ids_.Equals(other.ids_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= ids_.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) { + ids_.WriteTo(output, _repeated_ids_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += ids_.CalculateSize(_repeated_ids_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(InvTransactionsMessage other) { + if (other == null) { + return; + } + ids_.Add(other.ids_); + _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: { + ids_.AddEntriesFrom(input, _repeated_ids_codec); + break; + } + } + } + } + + } + + public sealed partial class PingMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PingMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[24]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PingMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PingMessage(PingMessage other) : this() { + nonce_ = other.nonce_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PingMessage Clone() { + return new PingMessage(this); + } + + /// Field number for the "nonce" field. + public const int NonceFieldNumber = 1; + private ulong nonce_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Nonce { + get { return nonce_; } + set { + nonce_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PingMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PingMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Nonce != other.Nonce) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Nonce != 0UL) hash ^= Nonce.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 (Nonce != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Nonce); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Nonce != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Nonce); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PingMessage other) { + if (other == null) { + return; + } + if (other.Nonce != 0UL) { + Nonce = other.Nonce; + } + _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 8: { + Nonce = input.ReadUInt64(); + break; + } + } + } + } + + } + + public sealed partial class PongMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PongMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[25]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PongMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PongMessage(PongMessage other) : this() { + nonce_ = other.nonce_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PongMessage Clone() { + return new PongMessage(this); + } + + /// Field number for the "nonce" field. + public const int NonceFieldNumber = 1; + private ulong nonce_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Nonce { + get { return nonce_; } + set { + nonce_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PongMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PongMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Nonce != other.Nonce) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Nonce != 0UL) hash ^= Nonce.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 (Nonce != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Nonce); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Nonce != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Nonce); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PongMessage other) { + if (other == null) { + return; + } + if (other.Nonce != 0UL) { + Nonce = other.Nonce; + } + _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 8: { + Nonce = input.ReadUInt64(); + break; + } + } + } + } + + } + + public sealed partial class VerackMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new VerackMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[26]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VerackMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VerackMessage(VerackMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VerackMessage Clone() { + return new VerackMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as VerackMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(VerackMessage 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(VerackMessage 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 VersionMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new VersionMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[27]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VersionMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VersionMessage(VersionMessage other) : this() { + protocolVersion_ = other.protocolVersion_; + services_ = other.services_; + timestamp_ = other.timestamp_; + address_ = other.address_ != null ? other.address_.Clone() : null; + id_ = other.id_; + userAgent_ = other.userAgent_; + disableRelayTx_ = other.disableRelayTx_; + subnetworkId_ = other.subnetworkId_ != null ? other.subnetworkId_.Clone() : null; + network_ = other.network_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VersionMessage Clone() { + return new VersionMessage(this); + } + + /// Field number for the "protocolVersion" field. + public const int ProtocolVersionFieldNumber = 1; + private uint protocolVersion_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint ProtocolVersion { + get { return protocolVersion_; } + set { + protocolVersion_ = value; + } + } + + /// Field number for the "services" field. + public const int ServicesFieldNumber = 2; + private ulong services_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Services { + get { return services_; } + set { + services_ = value; + } + } + + /// Field number for the "timestamp" field. + public const int TimestampFieldNumber = 3; + private long timestamp_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Timestamp { + get { return timestamp_; } + set { + timestamp_ = value; + } + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 4; + private global::Miningcore.Blockchain.Kaspa.Kaspad.NetAddress address_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.NetAddress Address { + get { return address_; } + set { + address_ = value; + } + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 5; + private pb::ByteString id_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString Id { + get { return id_; } + set { + id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "userAgent" field. + public const int UserAgentFieldNumber = 6; + private string userAgent_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserAgent { + get { return userAgent_; } + set { + userAgent_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "disableRelayTx" field. + public const int DisableRelayTxFieldNumber = 8; + private bool disableRelayTx_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool DisableRelayTx { + get { return disableRelayTx_; } + set { + disableRelayTx_ = value; + } + } + + /// Field number for the "subnetworkId" field. + public const int SubnetworkIdFieldNumber = 9; + private global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId subnetworkId_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId SubnetworkId { + get { return subnetworkId_; } + set { + subnetworkId_ = value; + } + } + + /// Field number for the "network" field. + public const int NetworkFieldNumber = 10; + private string network_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Network { + get { return network_; } + set { + network_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as VersionMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(VersionMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ProtocolVersion != other.ProtocolVersion) return false; + if (Services != other.Services) return false; + if (Timestamp != other.Timestamp) return false; + if (!object.Equals(Address, other.Address)) return false; + if (Id != other.Id) return false; + if (UserAgent != other.UserAgent) return false; + if (DisableRelayTx != other.DisableRelayTx) return false; + if (!object.Equals(SubnetworkId, other.SubnetworkId)) return false; + if (Network != other.Network) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ProtocolVersion != 0) hash ^= ProtocolVersion.GetHashCode(); + if (Services != 0UL) hash ^= Services.GetHashCode(); + if (Timestamp != 0L) hash ^= Timestamp.GetHashCode(); + if (address_ != null) hash ^= Address.GetHashCode(); + if (Id.Length != 0) hash ^= Id.GetHashCode(); + if (UserAgent.Length != 0) hash ^= UserAgent.GetHashCode(); + if (DisableRelayTx != false) hash ^= DisableRelayTx.GetHashCode(); + if (subnetworkId_ != null) hash ^= SubnetworkId.GetHashCode(); + if (Network.Length != 0) hash ^= Network.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 (ProtocolVersion != 0) { + output.WriteRawTag(8); + output.WriteUInt32(ProtocolVersion); + } + if (Services != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(Services); + } + if (Timestamp != 0L) { + output.WriteRawTag(24); + output.WriteInt64(Timestamp); + } + if (address_ != null) { + output.WriteRawTag(34); + output.WriteMessage(Address); + } + if (Id.Length != 0) { + output.WriteRawTag(42); + output.WriteBytes(Id); + } + if (UserAgent.Length != 0) { + output.WriteRawTag(50); + output.WriteString(UserAgent); + } + if (DisableRelayTx != false) { + output.WriteRawTag(64); + output.WriteBool(DisableRelayTx); + } + if (subnetworkId_ != null) { + output.WriteRawTag(74); + output.WriteMessage(SubnetworkId); + } + if (Network.Length != 0) { + output.WriteRawTag(82); + output.WriteString(Network); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ProtocolVersion != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(ProtocolVersion); + } + if (Services != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Services); + } + if (Timestamp != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Timestamp); + } + if (address_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Address); + } + if (Id.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Id); + } + if (UserAgent.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserAgent); + } + if (DisableRelayTx != false) { + size += 1 + 1; + } + if (subnetworkId_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SubnetworkId); + } + if (Network.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Network); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(VersionMessage other) { + if (other == null) { + return; + } + if (other.ProtocolVersion != 0) { + ProtocolVersion = other.ProtocolVersion; + } + if (other.Services != 0UL) { + Services = other.Services; + } + if (other.Timestamp != 0L) { + Timestamp = other.Timestamp; + } + if (other.address_ != null) { + if (address_ == null) { + Address = new global::Miningcore.Blockchain.Kaspa.Kaspad.NetAddress(); + } + Address.MergeFrom(other.Address); + } + if (other.Id.Length != 0) { + Id = other.Id; + } + if (other.UserAgent.Length != 0) { + UserAgent = other.UserAgent; + } + if (other.DisableRelayTx != false) { + DisableRelayTx = other.DisableRelayTx; + } + if (other.subnetworkId_ != null) { + if (subnetworkId_ == null) { + SubnetworkId = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId(); + } + SubnetworkId.MergeFrom(other.SubnetworkId); + } + if (other.Network.Length != 0) { + Network = other.Network; + } + _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 8: { + ProtocolVersion = input.ReadUInt32(); + break; + } + case 16: { + Services = input.ReadUInt64(); + break; + } + case 24: { + Timestamp = input.ReadInt64(); + break; + } + case 34: { + if (address_ == null) { + Address = new global::Miningcore.Blockchain.Kaspa.Kaspad.NetAddress(); + } + input.ReadMessage(Address); + break; + } + case 42: { + Id = input.ReadBytes(); + break; + } + case 50: { + UserAgent = input.ReadString(); + break; + } + case 64: { + DisableRelayTx = input.ReadBool(); + break; + } + case 74: { + if (subnetworkId_ == null) { + SubnetworkId = new global::Miningcore.Blockchain.Kaspa.Kaspad.SubnetworkId(); + } + input.ReadMessage(SubnetworkId); + break; + } + case 82: { + Network = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RejectMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RejectMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[28]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RejectMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RejectMessage(RejectMessage other) : this() { + reason_ = other.reason_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RejectMessage Clone() { + return new RejectMessage(this); + } + + /// Field number for the "reason" field. + public const int ReasonFieldNumber = 1; + private string reason_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Reason { + get { return reason_; } + set { + reason_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RejectMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RejectMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Reason != other.Reason) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Reason.Length != 0) hash ^= Reason.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 (Reason.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Reason); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Reason.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Reason); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RejectMessage other) { + if (other == null) { + return; + } + if (other.Reason.Length != 0) { + Reason = other.Reason; + } + _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: { + Reason = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RequestPruningPointUTXOSetMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestPruningPointUTXOSetMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[29]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointUTXOSetMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointUTXOSetMessage(RequestPruningPointUTXOSetMessage other) : this() { + pruningPointHash_ = other.pruningPointHash_ != null ? other.pruningPointHash_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointUTXOSetMessage Clone() { + return new RequestPruningPointUTXOSetMessage(this); + } + + /// Field number for the "pruningPointHash" field. + public const int PruningPointHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash pruningPointHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash PruningPointHash { + get { return pruningPointHash_; } + set { + pruningPointHash_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestPruningPointUTXOSetMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestPruningPointUTXOSetMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(PruningPointHash, other.PruningPointHash)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (pruningPointHash_ != null) hash ^= PruningPointHash.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 (pruningPointHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(PruningPointHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (pruningPointHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PruningPointHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestPruningPointUTXOSetMessage other) { + if (other == null) { + return; + } + if (other.pruningPointHash_ != null) { + if (pruningPointHash_ == null) { + PruningPointHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + PruningPointHash.MergeFrom(other.PruningPointHash); + } + _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: { + if (pruningPointHash_ == null) { + PruningPointHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(PruningPointHash); + break; + } + } + } + } + + } + + public sealed partial class PruningPointUtxoSetChunkMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PruningPointUtxoSetChunkMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[30]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointUtxoSetChunkMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointUtxoSetChunkMessage(PruningPointUtxoSetChunkMessage other) : this() { + outpointAndUtxoEntryPairs_ = other.outpointAndUtxoEntryPairs_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointUtxoSetChunkMessage Clone() { + return new PruningPointUtxoSetChunkMessage(this); + } + + /// Field number for the "outpointAndUtxoEntryPairs" field. + public const int OutpointAndUtxoEntryPairsFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_outpointAndUtxoEntryPairs_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.OutpointAndUtxoEntryPair.Parser); + private readonly pbc::RepeatedField outpointAndUtxoEntryPairs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField OutpointAndUtxoEntryPairs { + get { return outpointAndUtxoEntryPairs_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PruningPointUtxoSetChunkMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PruningPointUtxoSetChunkMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!outpointAndUtxoEntryPairs_.Equals(other.outpointAndUtxoEntryPairs_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= outpointAndUtxoEntryPairs_.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) { + outpointAndUtxoEntryPairs_.WriteTo(output, _repeated_outpointAndUtxoEntryPairs_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += outpointAndUtxoEntryPairs_.CalculateSize(_repeated_outpointAndUtxoEntryPairs_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PruningPointUtxoSetChunkMessage other) { + if (other == null) { + return; + } + outpointAndUtxoEntryPairs_.Add(other.outpointAndUtxoEntryPairs_); + _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: { + outpointAndUtxoEntryPairs_.AddEntriesFrom(input, _repeated_outpointAndUtxoEntryPairs_codec); + break; + } + } + } + } + + } + + public sealed partial class OutpointAndUtxoEntryPair : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new OutpointAndUtxoEntryPair()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[31]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OutpointAndUtxoEntryPair() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OutpointAndUtxoEntryPair(OutpointAndUtxoEntryPair other) : this() { + outpoint_ = other.outpoint_ != null ? other.outpoint_.Clone() : null; + utxoEntry_ = other.utxoEntry_ != null ? other.utxoEntry_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public OutpointAndUtxoEntryPair Clone() { + return new OutpointAndUtxoEntryPair(this); + } + + /// Field number for the "outpoint" field. + public const int OutpointFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint outpoint_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint Outpoint { + get { return outpoint_; } + set { + outpoint_ = value; + } + } + + /// Field number for the "utxoEntry" field. + public const int UtxoEntryFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.UtxoEntry utxoEntry_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.UtxoEntry UtxoEntry { + get { return utxoEntry_; } + set { + utxoEntry_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as OutpointAndUtxoEntryPair); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(OutpointAndUtxoEntryPair other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Outpoint, other.Outpoint)) return false; + if (!object.Equals(UtxoEntry, other.UtxoEntry)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (outpoint_ != null) hash ^= Outpoint.GetHashCode(); + if (utxoEntry_ != null) hash ^= UtxoEntry.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 (outpoint_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Outpoint); + } + if (utxoEntry_ != null) { + output.WriteRawTag(18); + output.WriteMessage(UtxoEntry); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (outpoint_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Outpoint); + } + if (utxoEntry_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(UtxoEntry); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(OutpointAndUtxoEntryPair other) { + if (other == null) { + return; + } + if (other.outpoint_ != null) { + if (outpoint_ == null) { + Outpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint(); + } + Outpoint.MergeFrom(other.Outpoint); + } + if (other.utxoEntry_ != null) { + if (utxoEntry_ == null) { + UtxoEntry = new global::Miningcore.Blockchain.Kaspa.Kaspad.UtxoEntry(); + } + UtxoEntry.MergeFrom(other.UtxoEntry); + } + _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: { + if (outpoint_ == null) { + Outpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.Outpoint(); + } + input.ReadMessage(Outpoint); + break; + } + case 18: { + if (utxoEntry_ == null) { + UtxoEntry = new global::Miningcore.Blockchain.Kaspa.Kaspad.UtxoEntry(); + } + input.ReadMessage(UtxoEntry); + break; + } + } + } + } + + } + + public sealed partial class UtxoEntry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UtxoEntry()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[32]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxoEntry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxoEntry(UtxoEntry other) : this() { + amount_ = other.amount_; + scriptPublicKey_ = other.scriptPublicKey_ != null ? other.scriptPublicKey_.Clone() : null; + blockDaaScore_ = other.blockDaaScore_; + isCoinbase_ = other.isCoinbase_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxoEntry Clone() { + return new UtxoEntry(this); + } + + /// Field number for the "amount" field. + public const int AmountFieldNumber = 1; + private ulong amount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Amount { + get { return amount_; } + set { + amount_ = value; + } + } + + /// Field number for the "scriptPublicKey" field. + public const int ScriptPublicKeyFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey scriptPublicKey_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey ScriptPublicKey { + get { return scriptPublicKey_; } + set { + scriptPublicKey_ = value; + } + } + + /// Field number for the "blockDaaScore" field. + public const int BlockDaaScoreFieldNumber = 3; + private ulong blockDaaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlockDaaScore { + get { return blockDaaScore_; } + set { + blockDaaScore_ = value; + } + } + + /// Field number for the "isCoinbase" field. + public const int IsCoinbaseFieldNumber = 4; + private bool isCoinbase_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsCoinbase { + get { return isCoinbase_; } + set { + isCoinbase_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UtxoEntry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UtxoEntry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Amount != other.Amount) return false; + if (!object.Equals(ScriptPublicKey, other.ScriptPublicKey)) return false; + if (BlockDaaScore != other.BlockDaaScore) return false; + if (IsCoinbase != other.IsCoinbase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Amount != 0UL) hash ^= Amount.GetHashCode(); + if (scriptPublicKey_ != null) hash ^= ScriptPublicKey.GetHashCode(); + if (BlockDaaScore != 0UL) hash ^= BlockDaaScore.GetHashCode(); + if (IsCoinbase != false) hash ^= IsCoinbase.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 (Amount != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Amount); + } + if (scriptPublicKey_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ScriptPublicKey); + } + if (BlockDaaScore != 0UL) { + output.WriteRawTag(24); + output.WriteUInt64(BlockDaaScore); + } + if (IsCoinbase != false) { + output.WriteRawTag(32); + output.WriteBool(IsCoinbase); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Amount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Amount); + } + if (scriptPublicKey_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ScriptPublicKey); + } + if (BlockDaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlockDaaScore); + } + if (IsCoinbase != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UtxoEntry other) { + if (other == null) { + return; + } + if (other.Amount != 0UL) { + Amount = other.Amount; + } + if (other.scriptPublicKey_ != null) { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey(); + } + ScriptPublicKey.MergeFrom(other.ScriptPublicKey); + } + if (other.BlockDaaScore != 0UL) { + BlockDaaScore = other.BlockDaaScore; + } + if (other.IsCoinbase != false) { + IsCoinbase = other.IsCoinbase; + } + _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 8: { + Amount = input.ReadUInt64(); + break; + } + case 18: { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.ScriptPublicKey(); + } + input.ReadMessage(ScriptPublicKey); + break; + } + case 24: { + BlockDaaScore = input.ReadUInt64(); + break; + } + case 32: { + IsCoinbase = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class RequestNextPruningPointUtxoSetChunkMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestNextPruningPointUtxoSetChunkMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[33]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextPruningPointUtxoSetChunkMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextPruningPointUtxoSetChunkMessage(RequestNextPruningPointUtxoSetChunkMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextPruningPointUtxoSetChunkMessage Clone() { + return new RequestNextPruningPointUtxoSetChunkMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestNextPruningPointUtxoSetChunkMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestNextPruningPointUtxoSetChunkMessage 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(RequestNextPruningPointUtxoSetChunkMessage 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 DonePruningPointUtxoSetChunksMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DonePruningPointUtxoSetChunksMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[34]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DonePruningPointUtxoSetChunksMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DonePruningPointUtxoSetChunksMessage(DonePruningPointUtxoSetChunksMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DonePruningPointUtxoSetChunksMessage Clone() { + return new DonePruningPointUtxoSetChunksMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DonePruningPointUtxoSetChunksMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DonePruningPointUtxoSetChunksMessage 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(DonePruningPointUtxoSetChunksMessage 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 RequestIBDBlocksMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestIBDBlocksMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[35]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestIBDBlocksMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestIBDBlocksMessage(RequestIBDBlocksMessage other) : this() { + hashes_ = other.hashes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestIBDBlocksMessage Clone() { + return new RequestIBDBlocksMessage(this); + } + + /// Field number for the "hashes" field. + public const int HashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_hashes_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField hashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Hashes { + get { return hashes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestIBDBlocksMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestIBDBlocksMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!hashes_.Equals(other.hashes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= hashes_.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) { + hashes_.WriteTo(output, _repeated_hashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += hashes_.CalculateSize(_repeated_hashes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestIBDBlocksMessage other) { + if (other == null) { + return; + } + hashes_.Add(other.hashes_); + _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: { + hashes_.AddEntriesFrom(input, _repeated_hashes_codec); + break; + } + } + } + } + + } + + public sealed partial class UnexpectedPruningPointMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UnexpectedPruningPointMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[36]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnexpectedPruningPointMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnexpectedPruningPointMessage(UnexpectedPruningPointMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnexpectedPruningPointMessage Clone() { + return new UnexpectedPruningPointMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UnexpectedPruningPointMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UnexpectedPruningPointMessage 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(UnexpectedPruningPointMessage 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 IbdBlockLocatorMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new IbdBlockLocatorMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[37]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorMessage(IbdBlockLocatorMessage other) : this() { + targetHash_ = other.targetHash_ != null ? other.targetHash_.Clone() : null; + blockLocatorHashes_ = other.blockLocatorHashes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorMessage Clone() { + return new IbdBlockLocatorMessage(this); + } + + /// Field number for the "targetHash" field. + public const int TargetHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash targetHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash TargetHash { + get { return targetHash_; } + set { + targetHash_ = value; + } + } + + /// Field number for the "blockLocatorHashes" field. + public const int BlockLocatorHashesFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_blockLocatorHashes_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField blockLocatorHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField BlockLocatorHashes { + get { return blockLocatorHashes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as IbdBlockLocatorMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(IbdBlockLocatorMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(TargetHash, other.TargetHash)) return false; + if(!blockLocatorHashes_.Equals(other.blockLocatorHashes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (targetHash_ != null) hash ^= TargetHash.GetHashCode(); + hash ^= blockLocatorHashes_.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 (targetHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(TargetHash); + } + blockLocatorHashes_.WriteTo(output, _repeated_blockLocatorHashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (targetHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(TargetHash); + } + size += blockLocatorHashes_.CalculateSize(_repeated_blockLocatorHashes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(IbdBlockLocatorMessage other) { + if (other == null) { + return; + } + if (other.targetHash_ != null) { + if (targetHash_ == null) { + TargetHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + TargetHash.MergeFrom(other.TargetHash); + } + blockLocatorHashes_.Add(other.blockLocatorHashes_); + _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: { + if (targetHash_ == null) { + TargetHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(TargetHash); + break; + } + case 18: { + blockLocatorHashes_.AddEntriesFrom(input, _repeated_blockLocatorHashes_codec); + break; + } + } + } + } + + } + + public sealed partial class RequestIBDChainBlockLocatorMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestIBDChainBlockLocatorMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[38]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestIBDChainBlockLocatorMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestIBDChainBlockLocatorMessage(RequestIBDChainBlockLocatorMessage other) : this() { + lowHash_ = other.lowHash_ != null ? other.lowHash_.Clone() : null; + highHash_ = other.highHash_ != null ? other.highHash_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestIBDChainBlockLocatorMessage Clone() { + return new RequestIBDChainBlockLocatorMessage(this); + } + + /// Field number for the "lowHash" field. + public const int LowHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash lowHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash LowHash { + get { return lowHash_; } + set { + lowHash_ = value; + } + } + + /// Field number for the "highHash" field. + public const int HighHashFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash highHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash HighHash { + get { return highHash_; } + set { + highHash_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestIBDChainBlockLocatorMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestIBDChainBlockLocatorMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(LowHash, other.LowHash)) return false; + if (!object.Equals(HighHash, other.HighHash)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (lowHash_ != null) hash ^= LowHash.GetHashCode(); + if (highHash_ != null) hash ^= HighHash.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 (lowHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(LowHash); + } + if (highHash_ != null) { + output.WriteRawTag(18); + output.WriteMessage(HighHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (lowHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(LowHash); + } + if (highHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(HighHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestIBDChainBlockLocatorMessage other) { + if (other == null) { + return; + } + if (other.lowHash_ != null) { + if (lowHash_ == null) { + LowHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + LowHash.MergeFrom(other.LowHash); + } + if (other.highHash_ != null) { + if (highHash_ == null) { + HighHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + HighHash.MergeFrom(other.HighHash); + } + _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: { + if (lowHash_ == null) { + LowHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(LowHash); + break; + } + case 18: { + if (highHash_ == null) { + HighHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(HighHash); + break; + } + } + } + } + + } + + public sealed partial class IbdChainBlockLocatorMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new IbdChainBlockLocatorMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[39]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdChainBlockLocatorMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdChainBlockLocatorMessage(IbdChainBlockLocatorMessage other) : this() { + blockLocatorHashes_ = other.blockLocatorHashes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdChainBlockLocatorMessage Clone() { + return new IbdChainBlockLocatorMessage(this); + } + + /// Field number for the "blockLocatorHashes" field. + public const int BlockLocatorHashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_blockLocatorHashes_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField blockLocatorHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField BlockLocatorHashes { + get { return blockLocatorHashes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as IbdChainBlockLocatorMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(IbdChainBlockLocatorMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!blockLocatorHashes_.Equals(other.blockLocatorHashes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= blockLocatorHashes_.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) { + blockLocatorHashes_.WriteTo(output, _repeated_blockLocatorHashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += blockLocatorHashes_.CalculateSize(_repeated_blockLocatorHashes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(IbdChainBlockLocatorMessage other) { + if (other == null) { + return; + } + blockLocatorHashes_.Add(other.blockLocatorHashes_); + _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: { + blockLocatorHashes_.AddEntriesFrom(input, _repeated_blockLocatorHashes_codec); + break; + } + } + } + } + + } + + public sealed partial class RequestAnticoneMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestAnticoneMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[40]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestAnticoneMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestAnticoneMessage(RequestAnticoneMessage other) : this() { + blockHash_ = other.blockHash_ != null ? other.blockHash_.Clone() : null; + contextHash_ = other.contextHash_ != null ? other.contextHash_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestAnticoneMessage Clone() { + return new RequestAnticoneMessage(this); + } + + /// Field number for the "blockHash" field. + public const int BlockHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash blockHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash BlockHash { + get { return blockHash_; } + set { + blockHash_ = value; + } + } + + /// Field number for the "contextHash" field. + public const int ContextHashFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash contextHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash ContextHash { + get { return contextHash_; } + set { + contextHash_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestAnticoneMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestAnticoneMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(BlockHash, other.BlockHash)) return false; + if (!object.Equals(ContextHash, other.ContextHash)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (blockHash_ != null) hash ^= BlockHash.GetHashCode(); + if (contextHash_ != null) hash ^= ContextHash.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 (blockHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(BlockHash); + } + if (contextHash_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ContextHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (blockHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(BlockHash); + } + if (contextHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ContextHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RequestAnticoneMessage other) { + if (other == null) { + return; + } + if (other.blockHash_ != null) { + if (blockHash_ == null) { + BlockHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + BlockHash.MergeFrom(other.BlockHash); + } + if (other.contextHash_ != null) { + if (contextHash_ == null) { + ContextHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + ContextHash.MergeFrom(other.ContextHash); + } + _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: { + if (blockHash_ == null) { + BlockHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(BlockHash); + break; + } + case 18: { + if (contextHash_ == null) { + ContextHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(ContextHash); + break; + } + } + } + } + + } + + public sealed partial class IbdBlockLocatorHighestHashMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new IbdBlockLocatorHighestHashMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[41]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorHighestHashMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorHighestHashMessage(IbdBlockLocatorHighestHashMessage other) : this() { + highestHash_ = other.highestHash_ != null ? other.highestHash_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorHighestHashMessage Clone() { + return new IbdBlockLocatorHighestHashMessage(this); + } + + /// Field number for the "highestHash" field. + public const int HighestHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash highestHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash HighestHash { + get { return highestHash_; } + set { + highestHash_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as IbdBlockLocatorHighestHashMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(IbdBlockLocatorHighestHashMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(HighestHash, other.HighestHash)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (highestHash_ != null) hash ^= HighestHash.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 (highestHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(HighestHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (highestHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(HighestHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(IbdBlockLocatorHighestHashMessage other) { + if (other == null) { + return; + } + if (other.highestHash_ != null) { + if (highestHash_ == null) { + HighestHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + HighestHash.MergeFrom(other.HighestHash); + } + _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: { + if (highestHash_ == null) { + HighestHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(HighestHash); + break; + } + } + } + } + + } + + public sealed partial class IbdBlockLocatorHighestHashNotFoundMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new IbdBlockLocatorHighestHashNotFoundMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[42]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorHighestHashNotFoundMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorHighestHashNotFoundMessage(IbdBlockLocatorHighestHashNotFoundMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public IbdBlockLocatorHighestHashNotFoundMessage Clone() { + return new IbdBlockLocatorHighestHashNotFoundMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as IbdBlockLocatorHighestHashNotFoundMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(IbdBlockLocatorHighestHashNotFoundMessage 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(IbdBlockLocatorHighestHashNotFoundMessage 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 BlockHeadersMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockHeadersMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[43]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockHeadersMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockHeadersMessage(BlockHeadersMessage other) : this() { + blockHeaders_ = other.blockHeaders_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockHeadersMessage Clone() { + return new BlockHeadersMessage(this); + } + + /// Field number for the "blockHeaders" field. + public const int BlockHeadersFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_blockHeaders_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader.Parser); + private readonly pbc::RepeatedField blockHeaders_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField BlockHeaders { + get { return blockHeaders_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockHeadersMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockHeadersMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!blockHeaders_.Equals(other.blockHeaders_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= blockHeaders_.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) { + blockHeaders_.WriteTo(output, _repeated_blockHeaders_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += blockHeaders_.CalculateSize(_repeated_blockHeaders_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockHeadersMessage other) { + if (other == null) { + return; + } + blockHeaders_.Add(other.blockHeaders_); + _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: { + blockHeaders_.AddEntriesFrom(input, _repeated_blockHeaders_codec); + break; + } + } + } + } + + } + + public sealed partial class RequestPruningPointAndItsAnticoneMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestPruningPointAndItsAnticoneMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[44]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointAndItsAnticoneMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointAndItsAnticoneMessage(RequestPruningPointAndItsAnticoneMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointAndItsAnticoneMessage Clone() { + return new RequestPruningPointAndItsAnticoneMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestPruningPointAndItsAnticoneMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestPruningPointAndItsAnticoneMessage 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(RequestPruningPointAndItsAnticoneMessage 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 RequestNextPruningPointAndItsAnticoneBlocksMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestNextPruningPointAndItsAnticoneBlocksMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[45]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextPruningPointAndItsAnticoneBlocksMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextPruningPointAndItsAnticoneBlocksMessage(RequestNextPruningPointAndItsAnticoneBlocksMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestNextPruningPointAndItsAnticoneBlocksMessage Clone() { + return new RequestNextPruningPointAndItsAnticoneBlocksMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestNextPruningPointAndItsAnticoneBlocksMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestNextPruningPointAndItsAnticoneBlocksMessage 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(RequestNextPruningPointAndItsAnticoneBlocksMessage 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 BlockWithTrustedDataMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockWithTrustedDataMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[46]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockWithTrustedDataMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockWithTrustedDataMessage(BlockWithTrustedDataMessage other) : this() { + block_ = other.block_ != null ? other.block_.Clone() : null; + daaScore_ = other.daaScore_; + daaWindow_ = other.daaWindow_.Clone(); + ghostdagData_ = other.ghostdagData_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockWithTrustedDataMessage Clone() { + return new BlockWithTrustedDataMessage(this); + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage block_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage Block { + get { return block_; } + set { + block_ = value; + } + } + + /// Field number for the "daaScore" field. + public const int DaaScoreFieldNumber = 2; + private ulong daaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong DaaScore { + get { return daaScore_; } + set { + daaScore_ = value; + } + } + + /// Field number for the "daaWindow" field. + public const int DaaWindowFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_daaWindow_codec + = pb::FieldCodec.ForMessage(26, global::Miningcore.Blockchain.Kaspa.Kaspad.DaaBlock.Parser); + private readonly pbc::RepeatedField daaWindow_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField DaaWindow { + get { return daaWindow_; } + } + + /// Field number for the "ghostdagData" field. + public const int GhostdagDataFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_ghostdagData_codec + = pb::FieldCodec.ForMessage(34, global::Miningcore.Blockchain.Kaspa.Kaspad.BlockGhostdagDataHashPair.Parser); + private readonly pbc::RepeatedField ghostdagData_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField GhostdagData { + get { return ghostdagData_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockWithTrustedDataMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockWithTrustedDataMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Block, other.Block)) return false; + if (DaaScore != other.DaaScore) return false; + if(!daaWindow_.Equals(other.daaWindow_)) return false; + if(!ghostdagData_.Equals(other.ghostdagData_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (block_ != null) hash ^= Block.GetHashCode(); + if (DaaScore != 0UL) hash ^= DaaScore.GetHashCode(); + hash ^= daaWindow_.GetHashCode(); + hash ^= ghostdagData_.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 (block_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Block); + } + if (DaaScore != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(DaaScore); + } + daaWindow_.WriteTo(output, _repeated_daaWindow_codec); + ghostdagData_.WriteTo(output, _repeated_ghostdagData_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (block_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + if (DaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(DaaScore); + } + size += daaWindow_.CalculateSize(_repeated_daaWindow_codec); + size += ghostdagData_.CalculateSize(_repeated_ghostdagData_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockWithTrustedDataMessage other) { + if (other == null) { + return; + } + if (other.block_ != null) { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + Block.MergeFrom(other.Block); + } + if (other.DaaScore != 0UL) { + DaaScore = other.DaaScore; + } + daaWindow_.Add(other.daaWindow_); + ghostdagData_.Add(other.ghostdagData_); + _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: { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + input.ReadMessage(Block); + break; + } + case 16: { + DaaScore = input.ReadUInt64(); + break; + } + case 26: { + daaWindow_.AddEntriesFrom(input, _repeated_daaWindow_codec); + break; + } + case 34: { + ghostdagData_.AddEntriesFrom(input, _repeated_ghostdagData_codec); + break; + } + } + } + } + + } + + public sealed partial class DaaBlock : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DaaBlock()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[47]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaaBlock() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaaBlock(DaaBlock other) : this() { + block_ = other.block_ != null ? other.block_.Clone() : null; + ghostdagData_ = other.ghostdagData_ != null ? other.ghostdagData_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaaBlock Clone() { + return new DaaBlock(this); + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage block_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage Block { + get { return block_; } + set { + block_ = value; + } + } + + /// Field number for the "ghostdagData" field. + public const int GhostdagDataFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData ghostdagData_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData GhostdagData { + get { return ghostdagData_; } + set { + ghostdagData_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DaaBlock); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DaaBlock other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Block, other.Block)) return false; + if (!object.Equals(GhostdagData, other.GhostdagData)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (block_ != null) hash ^= Block.GetHashCode(); + if (ghostdagData_ != null) hash ^= GhostdagData.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 (ghostdagData_ != null) { + output.WriteRawTag(18); + output.WriteMessage(GhostdagData); + } + if (block_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Block); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (block_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + if (ghostdagData_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(GhostdagData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DaaBlock other) { + if (other == null) { + return; + } + if (other.block_ != null) { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + Block.MergeFrom(other.Block); + } + if (other.ghostdagData_ != null) { + if (ghostdagData_ == null) { + GhostdagData = new global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData(); + } + GhostdagData.MergeFrom(other.GhostdagData); + } + _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 18: { + if (ghostdagData_ == null) { + GhostdagData = new global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData(); + } + input.ReadMessage(GhostdagData); + break; + } + case 26: { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + input.ReadMessage(Block); + break; + } + } + } + } + + } + + public sealed partial class DaaBlockV4 : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DaaBlockV4()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[48]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaaBlockV4() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaaBlockV4(DaaBlockV4 other) : this() { + header_ = other.header_ != null ? other.header_.Clone() : null; + ghostdagData_ = other.ghostdagData_ != null ? other.ghostdagData_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DaaBlockV4 Clone() { + return new DaaBlockV4(this); + } + + /// Field number for the "header" field. + public const int HeaderFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader header_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader Header { + get { return header_; } + set { + header_ = value; + } + } + + /// Field number for the "ghostdagData" field. + public const int GhostdagDataFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData ghostdagData_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData GhostdagData { + get { return ghostdagData_; } + set { + ghostdagData_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DaaBlockV4); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DaaBlockV4 other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Header, other.Header)) return false; + if (!object.Equals(GhostdagData, other.GhostdagData)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (header_ != null) hash ^= Header.GetHashCode(); + if (ghostdagData_ != null) hash ^= GhostdagData.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 (header_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Header); + } + if (ghostdagData_ != null) { + output.WriteRawTag(18); + output.WriteMessage(GhostdagData); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (header_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Header); + } + if (ghostdagData_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(GhostdagData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DaaBlockV4 other) { + if (other == null) { + return; + } + if (other.header_ != null) { + if (header_ == null) { + Header = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader(); + } + Header.MergeFrom(other.Header); + } + if (other.ghostdagData_ != null) { + if (ghostdagData_ == null) { + GhostdagData = new global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData(); + } + GhostdagData.MergeFrom(other.GhostdagData); + } + _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: { + if (header_ == null) { + Header = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader(); + } + input.ReadMessage(Header); + break; + } + case 18: { + if (ghostdagData_ == null) { + GhostdagData = new global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData(); + } + input.ReadMessage(GhostdagData); + break; + } + } + } + } + + } + + public sealed partial class BlockGhostdagDataHashPair : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockGhostdagDataHashPair()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[49]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockGhostdagDataHashPair() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockGhostdagDataHashPair(BlockGhostdagDataHashPair other) : this() { + hash_ = other.hash_ != null ? other.hash_.Clone() : null; + ghostdagData_ = other.ghostdagData_ != null ? other.ghostdagData_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockGhostdagDataHashPair Clone() { + return new BlockGhostdagDataHashPair(this); + } + + /// Field number for the "hash" field. + public const int HashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash hash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash Hash { + get { return hash_; } + set { + hash_ = value; + } + } + + /// Field number for the "ghostdagData" field. + public const int GhostdagDataFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData ghostdagData_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData GhostdagData { + get { return ghostdagData_; } + set { + ghostdagData_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockGhostdagDataHashPair); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockGhostdagDataHashPair other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Hash, other.Hash)) return false; + if (!object.Equals(GhostdagData, other.GhostdagData)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (hash_ != null) hash ^= Hash.GetHashCode(); + if (ghostdagData_ != null) hash ^= GhostdagData.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 (hash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Hash); + } + if (ghostdagData_ != null) { + output.WriteRawTag(18); + output.WriteMessage(GhostdagData); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (hash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Hash); + } + if (ghostdagData_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(GhostdagData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockGhostdagDataHashPair other) { + if (other == null) { + return; + } + if (other.hash_ != null) { + if (hash_ == null) { + Hash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + Hash.MergeFrom(other.Hash); + } + if (other.ghostdagData_ != null) { + if (ghostdagData_ == null) { + GhostdagData = new global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData(); + } + GhostdagData.MergeFrom(other.GhostdagData); + } + _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: { + if (hash_ == null) { + Hash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(Hash); + break; + } + case 18: { + if (ghostdagData_ == null) { + GhostdagData = new global::Miningcore.Blockchain.Kaspa.Kaspad.GhostdagData(); + } + input.ReadMessage(GhostdagData); + break; + } + } + } + } + + } + + public sealed partial class GhostdagData : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GhostdagData()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[50]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GhostdagData() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GhostdagData(GhostdagData other) : this() { + blueScore_ = other.blueScore_; + blueWork_ = other.blueWork_; + selectedParent_ = other.selectedParent_ != null ? other.selectedParent_.Clone() : null; + mergeSetBlues_ = other.mergeSetBlues_.Clone(); + mergeSetReds_ = other.mergeSetReds_.Clone(); + bluesAnticoneSizes_ = other.bluesAnticoneSizes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GhostdagData Clone() { + return new GhostdagData(this); + } + + /// Field number for the "blueScore" field. + public const int BlueScoreFieldNumber = 1; + private ulong blueScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlueScore { + get { return blueScore_; } + set { + blueScore_ = value; + } + } + + /// Field number for the "blueWork" field. + public const int BlueWorkFieldNumber = 2; + private pb::ByteString blueWork_ = pb::ByteString.Empty; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pb::ByteString BlueWork { + get { return blueWork_; } + set { + blueWork_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "selectedParent" field. + public const int SelectedParentFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash selectedParent_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash SelectedParent { + get { return selectedParent_; } + set { + selectedParent_ = value; + } + } + + /// Field number for the "mergeSetBlues" field. + public const int MergeSetBluesFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_mergeSetBlues_codec + = pb::FieldCodec.ForMessage(34, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField mergeSetBlues_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField MergeSetBlues { + get { return mergeSetBlues_; } + } + + /// Field number for the "mergeSetReds" field. + public const int MergeSetRedsFieldNumber = 5; + private static readonly pb::FieldCodec _repeated_mergeSetReds_codec + = pb::FieldCodec.ForMessage(42, global::Miningcore.Blockchain.Kaspa.Kaspad.Hash.Parser); + private readonly pbc::RepeatedField mergeSetReds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField MergeSetReds { + get { return mergeSetReds_; } + } + + /// Field number for the "bluesAnticoneSizes" field. + public const int BluesAnticoneSizesFieldNumber = 6; + private static readonly pb::FieldCodec _repeated_bluesAnticoneSizes_codec + = pb::FieldCodec.ForMessage(50, global::Miningcore.Blockchain.Kaspa.Kaspad.BluesAnticoneSizes.Parser); + private readonly pbc::RepeatedField bluesAnticoneSizes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField BluesAnticoneSizes { + get { return bluesAnticoneSizes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GhostdagData); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GhostdagData other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (BlueScore != other.BlueScore) return false; + if (BlueWork != other.BlueWork) return false; + if (!object.Equals(SelectedParent, other.SelectedParent)) return false; + if(!mergeSetBlues_.Equals(other.mergeSetBlues_)) return false; + if(!mergeSetReds_.Equals(other.mergeSetReds_)) return false; + if(!bluesAnticoneSizes_.Equals(other.bluesAnticoneSizes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (BlueScore != 0UL) hash ^= BlueScore.GetHashCode(); + if (BlueWork.Length != 0) hash ^= BlueWork.GetHashCode(); + if (selectedParent_ != null) hash ^= SelectedParent.GetHashCode(); + hash ^= mergeSetBlues_.GetHashCode(); + hash ^= mergeSetReds_.GetHashCode(); + hash ^= bluesAnticoneSizes_.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 (BlueScore != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(BlueScore); + } + if (BlueWork.Length != 0) { + output.WriteRawTag(18); + output.WriteBytes(BlueWork); + } + if (selectedParent_ != null) { + output.WriteRawTag(26); + output.WriteMessage(SelectedParent); + } + mergeSetBlues_.WriteTo(output, _repeated_mergeSetBlues_codec); + mergeSetReds_.WriteTo(output, _repeated_mergeSetReds_codec); + bluesAnticoneSizes_.WriteTo(output, _repeated_bluesAnticoneSizes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (BlueScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlueScore); + } + if (BlueWork.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(BlueWork); + } + if (selectedParent_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(SelectedParent); + } + size += mergeSetBlues_.CalculateSize(_repeated_mergeSetBlues_codec); + size += mergeSetReds_.CalculateSize(_repeated_mergeSetReds_codec); + size += bluesAnticoneSizes_.CalculateSize(_repeated_bluesAnticoneSizes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GhostdagData other) { + if (other == null) { + return; + } + if (other.BlueScore != 0UL) { + BlueScore = other.BlueScore; + } + if (other.BlueWork.Length != 0) { + BlueWork = other.BlueWork; + } + if (other.selectedParent_ != null) { + if (selectedParent_ == null) { + SelectedParent = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + SelectedParent.MergeFrom(other.SelectedParent); + } + mergeSetBlues_.Add(other.mergeSetBlues_); + mergeSetReds_.Add(other.mergeSetReds_); + bluesAnticoneSizes_.Add(other.bluesAnticoneSizes_); + _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 8: { + BlueScore = input.ReadUInt64(); + break; + } + case 18: { + BlueWork = input.ReadBytes(); + break; + } + case 26: { + if (selectedParent_ == null) { + SelectedParent = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(SelectedParent); + break; + } + case 34: { + mergeSetBlues_.AddEntriesFrom(input, _repeated_mergeSetBlues_codec); + break; + } + case 42: { + mergeSetReds_.AddEntriesFrom(input, _repeated_mergeSetReds_codec); + break; + } + case 50: { + bluesAnticoneSizes_.AddEntriesFrom(input, _repeated_bluesAnticoneSizes_codec); + break; + } + } + } + } + + } + + public sealed partial class BluesAnticoneSizes : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BluesAnticoneSizes()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[51]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BluesAnticoneSizes() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BluesAnticoneSizes(BluesAnticoneSizes other) : this() { + blueHash_ = other.blueHash_ != null ? other.blueHash_.Clone() : null; + anticoneSize_ = other.anticoneSize_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BluesAnticoneSizes Clone() { + return new BluesAnticoneSizes(this); + } + + /// Field number for the "blueHash" field. + public const int BlueHashFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.Hash blueHash_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.Hash BlueHash { + get { return blueHash_; } + set { + blueHash_ = value; + } + } + + /// Field number for the "anticoneSize" field. + public const int AnticoneSizeFieldNumber = 2; + private uint anticoneSize_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint AnticoneSize { + get { return anticoneSize_; } + set { + anticoneSize_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BluesAnticoneSizes); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BluesAnticoneSizes other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(BlueHash, other.BlueHash)) return false; + if (AnticoneSize != other.AnticoneSize) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (blueHash_ != null) hash ^= BlueHash.GetHashCode(); + if (AnticoneSize != 0) hash ^= AnticoneSize.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 (blueHash_ != null) { + output.WriteRawTag(10); + output.WriteMessage(BlueHash); + } + if (AnticoneSize != 0) { + output.WriteRawTag(16); + output.WriteUInt32(AnticoneSize); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (blueHash_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(BlueHash); + } + if (AnticoneSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(AnticoneSize); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BluesAnticoneSizes other) { + if (other == null) { + return; + } + if (other.blueHash_ != null) { + if (blueHash_ == null) { + BlueHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + BlueHash.MergeFrom(other.BlueHash); + } + if (other.AnticoneSize != 0) { + AnticoneSize = other.AnticoneSize; + } + _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: { + if (blueHash_ == null) { + BlueHash = new global::Miningcore.Blockchain.Kaspa.Kaspad.Hash(); + } + input.ReadMessage(BlueHash); + break; + } + case 16: { + AnticoneSize = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class DoneBlocksWithTrustedDataMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DoneBlocksWithTrustedDataMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[52]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DoneBlocksWithTrustedDataMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DoneBlocksWithTrustedDataMessage(DoneBlocksWithTrustedDataMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DoneBlocksWithTrustedDataMessage Clone() { + return new DoneBlocksWithTrustedDataMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DoneBlocksWithTrustedDataMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DoneBlocksWithTrustedDataMessage 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(DoneBlocksWithTrustedDataMessage 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 PruningPointsMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PruningPointsMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[53]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointsMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointsMessage(PruningPointsMessage other) : this() { + headers_ = other.headers_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointsMessage Clone() { + return new PruningPointsMessage(this); + } + + /// Field number for the "headers" field. + public const int HeadersFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_headers_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader.Parser); + private readonly pbc::RepeatedField headers_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Headers { + get { return headers_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PruningPointsMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PruningPointsMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!headers_.Equals(other.headers_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= headers_.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) { + headers_.WriteTo(output, _repeated_headers_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += headers_.CalculateSize(_repeated_headers_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PruningPointsMessage other) { + if (other == null) { + return; + } + headers_.Add(other.headers_); + _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: { + headers_.AddEntriesFrom(input, _repeated_headers_codec); + break; + } + } + } + } + + } + + public sealed partial class RequestPruningPointProofMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RequestPruningPointProofMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[54]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointProofMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointProofMessage(RequestPruningPointProofMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RequestPruningPointProofMessage Clone() { + return new RequestPruningPointProofMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RequestPruningPointProofMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RequestPruningPointProofMessage 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(RequestPruningPointProofMessage 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 PruningPointProofMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PruningPointProofMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[55]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointProofMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointProofMessage(PruningPointProofMessage other) : this() { + headers_ = other.headers_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointProofMessage Clone() { + return new PruningPointProofMessage(this); + } + + /// Field number for the "headers" field. + public const int HeadersFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_headers_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointProofHeaderArray.Parser); + private readonly pbc::RepeatedField headers_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Headers { + get { return headers_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PruningPointProofMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PruningPointProofMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!headers_.Equals(other.headers_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= headers_.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) { + headers_.WriteTo(output, _repeated_headers_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += headers_.CalculateSize(_repeated_headers_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PruningPointProofMessage other) { + if (other == null) { + return; + } + headers_.Add(other.headers_); + _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: { + headers_.AddEntriesFrom(input, _repeated_headers_codec); + break; + } + } + } + } + + } + + public sealed partial class PruningPointProofHeaderArray : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PruningPointProofHeaderArray()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[56]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointProofHeaderArray() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointProofHeaderArray(PruningPointProofHeaderArray other) : this() { + headers_ = other.headers_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointProofHeaderArray Clone() { + return new PruningPointProofHeaderArray(this); + } + + /// Field number for the "headers" field. + public const int HeadersFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_headers_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.BlockHeader.Parser); + private readonly pbc::RepeatedField headers_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Headers { + get { return headers_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PruningPointProofHeaderArray); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PruningPointProofHeaderArray other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!headers_.Equals(other.headers_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= headers_.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) { + headers_.WriteTo(output, _repeated_headers_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += headers_.CalculateSize(_repeated_headers_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(PruningPointProofHeaderArray other) { + if (other == null) { + return; + } + headers_.Add(other.headers_); + _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: { + headers_.AddEntriesFrom(input, _repeated_headers_codec); + break; + } + } + } + } + + } + + public sealed partial class ReadyMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ReadyMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[57]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ReadyMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ReadyMessage(ReadyMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ReadyMessage Clone() { + return new ReadyMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ReadyMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ReadyMessage 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(ReadyMessage 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 BlockWithTrustedDataV4Message : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockWithTrustedDataV4Message()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[58]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockWithTrustedDataV4Message() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockWithTrustedDataV4Message(BlockWithTrustedDataV4Message other) : this() { + block_ = other.block_ != null ? other.block_.Clone() : null; + daaWindowIndices_ = other.daaWindowIndices_.Clone(); + ghostdagDataIndices_ = other.ghostdagDataIndices_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockWithTrustedDataV4Message Clone() { + return new BlockWithTrustedDataV4Message(this); + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage block_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage Block { + get { return block_; } + set { + block_ = value; + } + } + + /// Field number for the "daaWindowIndices" field. + public const int DaaWindowIndicesFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_daaWindowIndices_codec + = pb::FieldCodec.ForUInt64(18); + private readonly pbc::RepeatedField daaWindowIndices_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField DaaWindowIndices { + get { return daaWindowIndices_; } + } + + /// Field number for the "ghostdagDataIndices" field. + public const int GhostdagDataIndicesFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_ghostdagDataIndices_codec + = pb::FieldCodec.ForUInt64(26); + private readonly pbc::RepeatedField ghostdagDataIndices_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField GhostdagDataIndices { + get { return ghostdagDataIndices_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockWithTrustedDataV4Message); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockWithTrustedDataV4Message other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Block, other.Block)) return false; + if(!daaWindowIndices_.Equals(other.daaWindowIndices_)) return false; + if(!ghostdagDataIndices_.Equals(other.ghostdagDataIndices_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (block_ != null) hash ^= Block.GetHashCode(); + hash ^= daaWindowIndices_.GetHashCode(); + hash ^= ghostdagDataIndices_.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 (block_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Block); + } + daaWindowIndices_.WriteTo(output, _repeated_daaWindowIndices_codec); + ghostdagDataIndices_.WriteTo(output, _repeated_ghostdagDataIndices_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (block_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + size += daaWindowIndices_.CalculateSize(_repeated_daaWindowIndices_codec); + size += ghostdagDataIndices_.CalculateSize(_repeated_ghostdagDataIndices_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockWithTrustedDataV4Message other) { + if (other == null) { + return; + } + if (other.block_ != null) { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + Block.MergeFrom(other.Block); + } + daaWindowIndices_.Add(other.daaWindowIndices_); + ghostdagDataIndices_.Add(other.ghostdagDataIndices_); + _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: { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.BlockMessage(); + } + input.ReadMessage(Block); + break; + } + case 18: + case 16: { + daaWindowIndices_.AddEntriesFrom(input, _repeated_daaWindowIndices_codec); + break; + } + case 26: + case 24: { + ghostdagDataIndices_.AddEntriesFrom(input, _repeated_ghostdagDataIndices_codec); + break; + } + } + } + } + + } + + public sealed partial class TrustedDataMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TrustedDataMessage()); + 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.Kaspad.P2PReflection.Descriptor.MessageTypes[59]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TrustedDataMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TrustedDataMessage(TrustedDataMessage other) : this() { + daaWindow_ = other.daaWindow_.Clone(); + ghostdagData_ = other.ghostdagData_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public TrustedDataMessage Clone() { + return new TrustedDataMessage(this); + } + + /// Field number for the "daaWindow" field. + public const int DaaWindowFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_daaWindow_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.DaaBlockV4.Parser); + private readonly pbc::RepeatedField daaWindow_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField DaaWindow { + get { return daaWindow_; } + } + + /// Field number for the "ghostdagData" field. + public const int GhostdagDataFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_ghostdagData_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.BlockGhostdagDataHashPair.Parser); + private readonly pbc::RepeatedField ghostdagData_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField GhostdagData { + get { return ghostdagData_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as TrustedDataMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(TrustedDataMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!daaWindow_.Equals(other.daaWindow_)) return false; + if(!ghostdagData_.Equals(other.ghostdagData_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= daaWindow_.GetHashCode(); + hash ^= ghostdagData_.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) { + daaWindow_.WriteTo(output, _repeated_daaWindow_codec); + ghostdagData_.WriteTo(output, _repeated_ghostdagData_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += daaWindow_.CalculateSize(_repeated_daaWindow_codec); + size += ghostdagData_.CalculateSize(_repeated_ghostdagData_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(TrustedDataMessage other) { + if (other == null) { + return; + } + daaWindow_.Add(other.daaWindow_); + ghostdagData_.Add(other.ghostdagData_); + _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: { + daaWindow_.AddEntriesFrom(input, _repeated_daaWindow_codec); + break; + } + case 18: { + ghostdagData_.AddEntriesFrom(input, _repeated_ghostdagData_codec); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs new file mode 100644 index 000000000..219093eed --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/Rpc.cs @@ -0,0 +1,17549 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: rpc.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +namespace Miningcore.Blockchain.Kaspa.Kaspad { + + using pb = global::Google.Protobuf; + using pbc = global::Google.Protobuf.Collections; + using pbr = global::Google.Protobuf.Reflection; + using scg = global::System.Collections.Generic; + + /// Holder for reflection information generated from rpc.proto + public static partial class RpcReflection { + + #region Descriptor + /// File descriptor for rpc.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static RpcReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "CglycGMucHJvdG8SCXByb3Rvd2lyZSIbCghSUENFcnJvchIPCgdtZXNzYWdl", + "GAEgASgJIpsBCghScGNCbG9jaxIpCgZoZWFkZXIYASABKAsyGS5wcm90b3dp", + "cmUuUnBjQmxvY2tIZWFkZXISLwoMdHJhbnNhY3Rpb25zGAIgAygLMhkucHJv", + "dG93aXJlLlJwY1RyYW5zYWN0aW9uEjMKC3ZlcmJvc2VEYXRhGAMgASgLMh4u", + "cHJvdG93aXJlLlJwY0Jsb2NrVmVyYm9zZURhdGEingIKDlJwY0Jsb2NrSGVh", + "ZGVyEg8KB3ZlcnNpb24YASABKA0SMAoHcGFyZW50cxgMIAMoCzIfLnByb3Rv", + "d2lyZS5ScGNCbG9ja0xldmVsUGFyZW50cxIWCg5oYXNoTWVya2xlUm9vdBgD", + "IAEoCRIcChRhY2NlcHRlZElkTWVya2xlUm9vdBgEIAEoCRIWCg51dHhvQ29t", + "bWl0bWVudBgFIAEoCRIRCgl0aW1lc3RhbXAYBiABKAMSDAoEYml0cxgHIAEo", + "DRINCgVub25jZRgIIAEoBBIQCghkYWFTY29yZRgJIAEoBBIQCghibHVlV29y", + "axgKIAEoCRIUCgxwcnVuaW5nUG9pbnQYDiABKAkSEQoJYmx1ZVNjb3JlGA0g", + "ASgEIiwKFFJwY0Jsb2NrTGV2ZWxQYXJlbnRzEhQKDHBhcmVudEhhc2hlcxgB", + "IAMoCSL7AQoTUnBjQmxvY2tWZXJib3NlRGF0YRIMCgRoYXNoGAEgASgJEhIK", + "CmRpZmZpY3VsdHkYCyABKAESGgoSc2VsZWN0ZWRQYXJlbnRIYXNoGA0gASgJ", + "EhYKDnRyYW5zYWN0aW9uSWRzGA4gAygJEhQKDGlzSGVhZGVyT25seRgPIAEo", + "CBIRCglibHVlU2NvcmUYECABKAQSFgoOY2hpbGRyZW5IYXNoZXMYESADKAkS", + "GwoTbWVyZ2VTZXRCbHVlc0hhc2hlcxgSIAMoCRIaChJtZXJnZVNldFJlZHNI", + "YXNoZXMYEyADKAkSFAoMaXNDaGFpbkJsb2NrGBQgASgIIoQCCg5ScGNUcmFu", + "c2FjdGlvbhIPCgd2ZXJzaW9uGAEgASgNEi4KBmlucHV0cxgCIAMoCzIeLnBy", + "b3Rvd2lyZS5ScGNUcmFuc2FjdGlvbklucHV0EjAKB291dHB1dHMYAyADKAsy", + "Hy5wcm90b3dpcmUuUnBjVHJhbnNhY3Rpb25PdXRwdXQSEAoIbG9ja1RpbWUY", + "BCABKAQSFAoMc3VibmV0d29ya0lkGAUgASgJEgsKA2dhcxgGIAEoBBIPCgdw", + "YXlsb2FkGAggASgJEjkKC3ZlcmJvc2VEYXRhGAkgASgLMiQucHJvdG93aXJl", + "LlJwY1RyYW5zYWN0aW9uVmVyYm9zZURhdGEixgEKE1JwY1RyYW5zYWN0aW9u", + "SW5wdXQSMAoQcHJldmlvdXNPdXRwb2ludBgBIAEoCzIWLnByb3Rvd2lyZS5S", + "cGNPdXRwb2ludBIXCg9zaWduYXR1cmVTY3JpcHQYAiABKAkSEAoIc2VxdWVu", + "Y2UYAyABKAQSEgoKc2lnT3BDb3VudBgFIAEoDRI+Cgt2ZXJib3NlRGF0YRgE", + "IAEoCzIpLnByb3Rvd2lyZS5ScGNUcmFuc2FjdGlvbklucHV0VmVyYm9zZURh", + "dGEiPgoSUnBjU2NyaXB0UHVibGljS2V5Eg8KB3ZlcnNpb24YASABKA0SFwoP", + "c2NyaXB0UHVibGljS2V5GAIgASgJIp8BChRScGNUcmFuc2FjdGlvbk91dHB1", + "dBIOCgZhbW91bnQYASABKAQSNgoPc2NyaXB0UHVibGljS2V5GAIgASgLMh0u", + "cHJvdG93aXJlLlJwY1NjcmlwdFB1YmxpY0tleRI/Cgt2ZXJib3NlRGF0YRgD", + "IAEoCzIqLnByb3Rvd2lyZS5ScGNUcmFuc2FjdGlvbk91dHB1dFZlcmJvc2VE", + "YXRhIjMKC1JwY091dHBvaW50EhUKDXRyYW5zYWN0aW9uSWQYASABKAkSDQoF", + "aW5kZXgYAiABKA0igQEKDFJwY1V0eG9FbnRyeRIOCgZhbW91bnQYASABKAQS", + "NgoPc2NyaXB0UHVibGljS2V5GAIgASgLMh0ucHJvdG93aXJlLlJwY1Njcmlw", + "dFB1YmxpY0tleRIVCg1ibG9ja0RhYVNjb3JlGAMgASgEEhIKCmlzQ29pbmJh", + "c2UYBCABKAgidAoZUnBjVHJhbnNhY3Rpb25WZXJib3NlRGF0YRIVCg10cmFu", + "c2FjdGlvbklkGAEgASgJEgwKBGhhc2gYAiABKAkSDAoEbWFzcxgEIAEoBBIR", + "CglibG9ja0hhc2gYDCABKAkSEQoJYmxvY2tUaW1lGA4gASgEIiAKHlJwY1Ry", + "YW5zYWN0aW9uSW5wdXRWZXJib3NlRGF0YSJeCh9ScGNUcmFuc2FjdGlvbk91", + "dHB1dFZlcmJvc2VEYXRhEhsKE3NjcmlwdFB1YmxpY0tleVR5cGUYBSABKAkS", + "HgoWc2NyaXB0UHVibGljS2V5QWRkcmVzcxgGIAEoCSIhCh9HZXRDdXJyZW50", + "TmV0d29ya1JlcXVlc3RNZXNzYWdlIl8KIEdldEN1cnJlbnROZXR3b3JrUmVz", + "cG9uc2VNZXNzYWdlEhYKDmN1cnJlbnROZXR3b3JrGAEgASgJEiMKBWVycm9y", + "GOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciJaChlTdWJtaXRCbG9ja1Jl", + "cXVlc3RNZXNzYWdlEiIKBWJsb2NrGAIgASgLMhMucHJvdG93aXJlLlJwY0Js", + "b2NrEhkKEWFsbG93Tm9uREFBQmxvY2tzGAMgASgIIscBChpTdWJtaXRCbG9j", + "a1Jlc3BvbnNlTWVzc2FnZRJICgxyZWplY3RSZWFzb24YASABKA4yMi5wcm90", + "b3dpcmUuU3VibWl0QmxvY2tSZXNwb25zZU1lc3NhZ2UuUmVqZWN0UmVhc29u", + "EiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciI6CgxSZWpl", + "Y3RSZWFzb24SCAoETk9ORRAAEhEKDUJMT0NLX0lOVkFMSUQQARINCglJU19J", + "Tl9JQkQQAiJHCh5HZXRCbG9ja1RlbXBsYXRlUmVxdWVzdE1lc3NhZ2USEgoK", + "cGF5QWRkcmVzcxgBIAEoCRIRCglleHRyYURhdGEYAiABKAkifAofR2V0Qmxv", + "Y2tUZW1wbGF0ZVJlc3BvbnNlTWVzc2FnZRIiCgVibG9jaxgDIAEoCzITLnBy", + "b3Rvd2lyZS5ScGNCbG9jaxIQCghpc1N5bmNlZBgCIAEoCBIjCgVlcnJvchjo", + "ByABKAsyEy5wcm90b3dpcmUuUlBDRXJyb3IiIAoeTm90aWZ5QmxvY2tBZGRl", + "ZFJlcXVlc3RNZXNzYWdlIkYKH05vdGlmeUJsb2NrQWRkZWRSZXNwb25zZU1l", + "c3NhZ2USIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJlLlJQQ0Vycm9yIkMK", + "HUJsb2NrQWRkZWROb3RpZmljYXRpb25NZXNzYWdlEiIKBWJsb2NrGAMgASgL", + "MhMucHJvdG93aXJlLlJwY0Jsb2NrIiAKHkdldFBlZXJBZGRyZXNzZXNSZXF1", + "ZXN0TWVzc2FnZSLSAQofR2V0UGVlckFkZHJlc3Nlc1Jlc3BvbnNlTWVzc2Fn", + "ZRJBCglhZGRyZXNzZXMYASADKAsyLi5wcm90b3dpcmUuR2V0UGVlckFkZHJl", + "c3Nlc0tub3duQWRkcmVzc01lc3NhZ2USRwoPYmFubmVkQWRkcmVzc2VzGAIg", + "AygLMi4ucHJvdG93aXJlLkdldFBlZXJBZGRyZXNzZXNLbm93bkFkZHJlc3NN", + "ZXNzYWdlEiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciIz", + "CiNHZXRQZWVyQWRkcmVzc2VzS25vd25BZGRyZXNzTWVzc2FnZRIMCgRBZGRy", + "GAEgASgJIiIKIEdldFNlbGVjdGVkVGlwSGFzaFJlcXVlc3RNZXNzYWdlImEK", + "IUdldFNlbGVjdGVkVGlwSGFzaFJlc3BvbnNlTWVzc2FnZRIXCg9zZWxlY3Rl", + "ZFRpcEhhc2gYASABKAkSIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJlLlJQ", + "Q0Vycm9yImcKHUdldE1lbXBvb2xFbnRyeVJlcXVlc3RNZXNzYWdlEgwKBHR4", + "SWQYASABKAkSGQoRaW5jbHVkZU9ycGhhblBvb2wYAiABKAgSHQoVZmlsdGVy", + "VHJhbnNhY3Rpb25Qb29sGAMgASgIIm0KHkdldE1lbXBvb2xFbnRyeVJlc3Bv", + "bnNlTWVzc2FnZRImCgVlbnRyeRgBIAEoCzIXLnByb3Rvd2lyZS5NZW1wb29s", + "RW50cnkSIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJlLlJQQ0Vycm9yIlsK", + "H0dldE1lbXBvb2xFbnRyaWVzUmVxdWVzdE1lc3NhZ2USGQoRaW5jbHVkZU9y", + "cGhhblBvb2wYASABKAgSHQoVZmlsdGVyVHJhbnNhY3Rpb25Qb29sGAIgASgI", + "InEKIEdldE1lbXBvb2xFbnRyaWVzUmVzcG9uc2VNZXNzYWdlEigKB2VudHJp", + "ZXMYASADKAsyFy5wcm90b3dpcmUuTWVtcG9vbEVudHJ5EiMKBWVycm9yGOgH", + "IAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciJdCgxNZW1wb29sRW50cnkSCwoD", + "ZmVlGAEgASgEEi4KC3RyYW5zYWN0aW9uGAMgASgLMhkucHJvdG93aXJlLlJw", + "Y1RyYW5zYWN0aW9uEhAKCGlzT3JwaGFuGAQgASgIIiQKIkdldENvbm5lY3Rl", + "ZFBlZXJJbmZvUmVxdWVzdE1lc3NhZ2UigQEKI0dldENvbm5lY3RlZFBlZXJJ", + "bmZvUmVzcG9uc2VNZXNzYWdlEjUKBWluZm9zGAEgAygLMiYucHJvdG93aXJl", + "LkdldENvbm5lY3RlZFBlZXJJbmZvTWVzc2FnZRIjCgVlcnJvchjoByABKAsy", + "Ey5wcm90b3dpcmUuUlBDRXJyb3Ii3AEKG0dldENvbm5lY3RlZFBlZXJJbmZv", + "TWVzc2FnZRIKCgJpZBgBIAEoCRIPCgdhZGRyZXNzGAIgASgJEhgKEGxhc3RQ", + "aW5nRHVyYXRpb24YAyABKAMSEgoKaXNPdXRib3VuZBgGIAEoCBISCgp0aW1l", + "T2Zmc2V0GAcgASgDEhEKCXVzZXJBZ2VudBgIIAEoCRIhChlhZHZlcnRpc2Vk", + "UHJvdG9jb2xWZXJzaW9uGAkgASgNEhUKDXRpbWVDb25uZWN0ZWQYCiABKAMS", + "EQoJaXNJYmRQZWVyGAsgASgIIj0KFUFkZFBlZXJSZXF1ZXN0TWVzc2FnZRIP", + "CgdhZGRyZXNzGAEgASgJEhMKC2lzUGVybWFuZW50GAIgASgIIj0KFkFkZFBl", + "ZXJSZXNwb25zZU1lc3NhZ2USIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJl", + "LlJQQ0Vycm9yImYKH1N1Ym1pdFRyYW5zYWN0aW9uUmVxdWVzdE1lc3NhZ2US", + "LgoLdHJhbnNhY3Rpb24YASABKAsyGS5wcm90b3dpcmUuUnBjVHJhbnNhY3Rp", + "b24SEwoLYWxsb3dPcnBoYW4YAiABKAgiXgogU3VibWl0VHJhbnNhY3Rpb25S", + "ZXNwb25zZU1lc3NhZ2USFQoNdHJhbnNhY3Rpb25JZBgBIAEoCRIjCgVlcnJv", + "chjoByABKAsyEy5wcm90b3dpcmUuUlBDRXJyb3IiXgo1Tm90aWZ5VmlydHVh", + "bFNlbGVjdGVkUGFyZW50Q2hhaW5DaGFuZ2VkUmVxdWVzdE1lc3NhZ2USJQod", + "aW5jbHVkZUFjY2VwdGVkVHJhbnNhY3Rpb25JZHMYASABKAgiXQo2Tm90aWZ5", + "VmlydHVhbFNlbGVjdGVkUGFyZW50Q2hhaW5DaGFuZ2VkUmVzcG9uc2VNZXNz", + "YWdlEiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciK5AQo0", + "VmlydHVhbFNlbGVjdGVkUGFyZW50Q2hhaW5DaGFuZ2VkTm90aWZpY2F0aW9u", + "TWVzc2FnZRIfChdyZW1vdmVkQ2hhaW5CbG9ja0hhc2hlcxgBIAMoCRIdChVh", + "ZGRlZENoYWluQmxvY2tIYXNoZXMYAyADKAkSQQoWYWNjZXB0ZWRUcmFuc2Fj", + "dGlvbklkcxgCIAMoCzIhLnByb3Rvd2lyZS5BY2NlcHRlZFRyYW5zYWN0aW9u", + "SWRzIkMKFkdldEJsb2NrUmVxdWVzdE1lc3NhZ2USDAoEaGFzaBgBIAEoCRIb", + "ChNpbmNsdWRlVHJhbnNhY3Rpb25zGAMgASgIImIKF0dldEJsb2NrUmVzcG9u", + "c2VNZXNzYWdlEiIKBWJsb2NrGAMgASgLMhMucHJvdG93aXJlLlJwY0Jsb2Nr", + "EiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciIzChtHZXRT", + "dWJuZXR3b3JrUmVxdWVzdE1lc3NhZ2USFAoMc3VibmV0d29ya0lkGAEgASgJ", + "IlUKHEdldFN1Ym5ldHdvcmtSZXNwb25zZU1lc3NhZ2USEAoIZ2FzTGltaXQY", + "ASABKAQSIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJlLlJQQ0Vycm9yInAK", + "NEdldFZpcnR1YWxTZWxlY3RlZFBhcmVudENoYWluRnJvbUJsb2NrUmVxdWVz", + "dE1lc3NhZ2USEQoJc3RhcnRIYXNoGAEgASgJEiUKHWluY2x1ZGVBY2NlcHRl", + "ZFRyYW5zYWN0aW9uSWRzGAIgASgIIlQKFkFjY2VwdGVkVHJhbnNhY3Rpb25J", + "ZHMSGgoSYWNjZXB0aW5nQmxvY2tIYXNoGAEgASgJEh4KFmFjY2VwdGVkVHJh", + "bnNhY3Rpb25JZHMYAiADKAki3wEKNUdldFZpcnR1YWxTZWxlY3RlZFBhcmVu", + "dENoYWluRnJvbUJsb2NrUmVzcG9uc2VNZXNzYWdlEh8KF3JlbW92ZWRDaGFp", + "bkJsb2NrSGFzaGVzGAEgAygJEh0KFWFkZGVkQ2hhaW5CbG9ja0hhc2hlcxgD", + "IAMoCRJBChZhY2NlcHRlZFRyYW5zYWN0aW9uSWRzGAIgAygLMiEucHJvdG93", + "aXJlLkFjY2VwdGVkVHJhbnNhY3Rpb25JZHMSIwoFZXJyb3IY6AcgASgLMhMu", + "cHJvdG93aXJlLlJQQ0Vycm9yIl4KF0dldEJsb2Nrc1JlcXVlc3RNZXNzYWdl", + "Eg8KB2xvd0hhc2gYASABKAkSFQoNaW5jbHVkZUJsb2NrcxgCIAEoCBIbChNp", + "bmNsdWRlVHJhbnNhY3Rpb25zGAMgASgIInkKGEdldEJsb2Nrc1Jlc3BvbnNl", + "TWVzc2FnZRITCgtibG9ja0hhc2hlcxgEIAMoCRIjCgZibG9ja3MYAyADKAsy", + "Ey5wcm90b3dpcmUuUnBjQmxvY2sSIwoFZXJyb3IY6AcgASgLMhMucHJvdG93", + "aXJlLlJQQ0Vycm9yIh0KG0dldEJsb2NrQ291bnRSZXF1ZXN0TWVzc2FnZSJs", + "ChxHZXRCbG9ja0NvdW50UmVzcG9uc2VNZXNzYWdlEhIKCmJsb2NrQ291bnQY", + "ASABKAQSEwoLaGVhZGVyQ291bnQYAiABKAQSIwoFZXJyb3IY6AcgASgLMhMu", + "cHJvdG93aXJlLlJQQ0Vycm9yIh8KHUdldEJsb2NrRGFnSW5mb1JlcXVlc3RN", + "ZXNzYWdlIpICCh5HZXRCbG9ja0RhZ0luZm9SZXNwb25zZU1lc3NhZ2USEwoL", + "bmV0d29ya05hbWUYASABKAkSEgoKYmxvY2tDb3VudBgCIAEoBBITCgtoZWFk", + "ZXJDb3VudBgDIAEoBBIRCgl0aXBIYXNoZXMYBCADKAkSEgoKZGlmZmljdWx0", + "eRgFIAEoARIWCg5wYXN0TWVkaWFuVGltZRgGIAEoAxIbChN2aXJ0dWFsUGFy", + "ZW50SGFzaGVzGAcgAygJEhgKEHBydW5pbmdQb2ludEhhc2gYCCABKAkSFwoP", + "dmlydHVhbERhYVNjb3JlGAkgASgEEiMKBWVycm9yGOgHIAEoCzITLnByb3Rv", + "d2lyZS5SUENFcnJvciJCCiVSZXNvbHZlRmluYWxpdHlDb25mbGljdFJlcXVl", + "c3RNZXNzYWdlEhkKEWZpbmFsaXR5QmxvY2tIYXNoGAEgASgJIk0KJlJlc29s", + "dmVGaW5hbGl0eUNvbmZsaWN0UmVzcG9uc2VNZXNzYWdlEiMKBWVycm9yGOgH", + "IAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciInCiVOb3RpZnlGaW5hbGl0eUNv", + "bmZsaWN0c1JlcXVlc3RNZXNzYWdlIk0KJk5vdGlmeUZpbmFsaXR5Q29uZmxp", + "Y3RzUmVzcG9uc2VNZXNzYWdlEiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2ly", + "ZS5SUENFcnJvciJBCiNGaW5hbGl0eUNvbmZsaWN0Tm90aWZpY2F0aW9uTWVz", + "c2FnZRIaChJ2aW9sYXRpbmdCbG9ja0hhc2gYASABKAkiSAorRmluYWxpdHlD", + "b25mbGljdFJlc29sdmVkTm90aWZpY2F0aW9uTWVzc2FnZRIZChFmaW5hbGl0", + "eUJsb2NrSGFzaBgBIAEoCSIYChZTaHV0RG93blJlcXVlc3RNZXNzYWdlIj4K", + "F1NodXREb3duUmVzcG9uc2VNZXNzYWdlEiMKBWVycm9yGOgHIAEoCzITLnBy", + "b3Rvd2lyZS5SUENFcnJvciJRChhHZXRIZWFkZXJzUmVxdWVzdE1lc3NhZ2US", + "EQoJc3RhcnRIYXNoGAEgASgJEg0KBWxpbWl0GAIgASgEEhMKC2lzQXNjZW5k", + "aW5nGAMgASgIIlEKGUdldEhlYWRlcnNSZXNwb25zZU1lc3NhZ2USDwoHaGVh", + "ZGVycxgBIAMoCRIjCgVlcnJvchjoByABKAsyEy5wcm90b3dpcmUuUlBDRXJy", + "b3IiNQogTm90aWZ5VXR4b3NDaGFuZ2VkUmVxdWVzdE1lc3NhZ2USEQoJYWRk", + "cmVzc2VzGAEgAygJIkgKIU5vdGlmeVV0eG9zQ2hhbmdlZFJlc3BvbnNlTWVz", + "c2FnZRIjCgVlcnJvchjoByABKAsyEy5wcm90b3dpcmUuUlBDRXJyb3IihQEK", + "H1V0eG9zQ2hhbmdlZE5vdGlmaWNhdGlvbk1lc3NhZ2USLwoFYWRkZWQYASAD", + "KAsyIC5wcm90b3dpcmUuVXR4b3NCeUFkZHJlc3Nlc0VudHJ5EjEKB3JlbW92", + "ZWQYAiADKAsyIC5wcm90b3dpcmUuVXR4b3NCeUFkZHJlc3Nlc0VudHJ5In4K", + "FVV0eG9zQnlBZGRyZXNzZXNFbnRyeRIPCgdhZGRyZXNzGAEgASgJEigKCG91", + "dHBvaW50GAIgASgLMhYucHJvdG93aXJlLlJwY091dHBvaW50EioKCXV0eG9F", + "bnRyeRgDIAEoCzIXLnByb3Rvd2lyZS5ScGNVdHhvRW50cnkiPAonU3RvcE5v", + "dGlmeWluZ1V0eG9zQ2hhbmdlZFJlcXVlc3RNZXNzYWdlEhEKCWFkZHJlc3Nl", + "cxgBIAMoCSJPCihTdG9wTm90aWZ5aW5nVXR4b3NDaGFuZ2VkUmVzcG9uc2VN", + "ZXNzYWdlEiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciI2", + "CiFHZXRVdHhvc0J5QWRkcmVzc2VzUmVxdWVzdE1lc3NhZ2USEQoJYWRkcmVz", + "c2VzGAEgAygJInwKIkdldFV0eG9zQnlBZGRyZXNzZXNSZXNwb25zZU1lc3Nh", + "Z2USMQoHZW50cmllcxgBIAMoCzIgLnByb3Rvd2lyZS5VdHhvc0J5QWRkcmVz", + "c2VzRW50cnkSIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJlLlJQQ0Vycm9y", + "IjQKIUdldEJhbGFuY2VCeUFkZHJlc3NSZXF1ZXN0TWVzc2FnZRIPCgdhZGRy", + "ZXNzGAEgASgJIloKIkdldEJhbGFuY2VCeUFkZHJlc3NSZXNwb25zZU1lc3Nh", + "Z2USDwoHYmFsYW5jZRgBIAEoBBIjCgVlcnJvchjoByABKAsyEy5wcm90b3dp", + "cmUuUlBDRXJyb3IiOQokR2V0QmFsYW5jZXNCeUFkZHJlc3Nlc1JlcXVlc3RN", + "ZXNzYWdlEhEKCWFkZHJlc3NlcxgBIAMoCSJfChZCYWxhbmNlc0J5QWRkcmVz", + "c0VudHJ5Eg8KB2FkZHJlc3MYASABKAkSDwoHYmFsYW5jZRgCIAEoBBIjCgVl", + "cnJvchjoByABKAsyEy5wcm90b3dpcmUuUlBDRXJyb3IigAEKJUdldEJhbGFu", + "Y2VzQnlBZGRyZXNzZXNSZXNwb25zZU1lc3NhZ2USMgoHZW50cmllcxgBIAMo", + "CzIhLnByb3Rvd2lyZS5CYWxhbmNlc0J5QWRkcmVzc0VudHJ5EiMKBWVycm9y", + "GOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciIxCi9HZXRWaXJ0dWFsU2Vs", + "ZWN0ZWRQYXJlbnRCbHVlU2NvcmVSZXF1ZXN0TWVzc2FnZSJqCjBHZXRWaXJ0", + "dWFsU2VsZWN0ZWRQYXJlbnRCbHVlU2NvcmVSZXNwb25zZU1lc3NhZ2USEQoJ", + "Ymx1ZVNjb3JlGAEgASgEEiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5S", + "UENFcnJvciI7CjlOb3RpZnlWaXJ0dWFsU2VsZWN0ZWRQYXJlbnRCbHVlU2Nv", + "cmVDaGFuZ2VkUmVxdWVzdE1lc3NhZ2UiYQo6Tm90aWZ5VmlydHVhbFNlbGVj", + "dGVkUGFyZW50Qmx1ZVNjb3JlQ2hhbmdlZFJlc3BvbnNlTWVzc2FnZRIjCgVl", + "cnJvchjoByABKAsyEy5wcm90b3dpcmUuUlBDRXJyb3IiYgo4VmlydHVhbFNl", + "bGVjdGVkUGFyZW50Qmx1ZVNjb3JlQ2hhbmdlZE5vdGlmaWNhdGlvbk1lc3Nh", + "Z2USJgoedmlydHVhbFNlbGVjdGVkUGFyZW50Qmx1ZVNjb3JlGAEgASgEIiwK", + "Kk5vdGlmeVZpcnR1YWxEYWFTY29yZUNoYW5nZWRSZXF1ZXN0TWVzc2FnZSJS", + "CitOb3RpZnlWaXJ0dWFsRGFhU2NvcmVDaGFuZ2VkUmVzcG9uc2VNZXNzYWdl", + "EiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciJECilWaXJ0", + "dWFsRGFhU2NvcmVDaGFuZ2VkTm90aWZpY2F0aW9uTWVzc2FnZRIXCg92aXJ0", + "dWFsRGFhU2NvcmUYASABKAQiMQovTm90aWZ5UHJ1bmluZ1BvaW50VVRYT1Nl", + "dE92ZXJyaWRlUmVxdWVzdE1lc3NhZ2UiVwowTm90aWZ5UHJ1bmluZ1BvaW50", + "VVRYT1NldE92ZXJyaWRlUmVzcG9uc2VNZXNzYWdlEiMKBWVycm9yGOgHIAEo", + "CzITLnByb3Rvd2lyZS5SUENFcnJvciIwCi5QcnVuaW5nUG9pbnRVVFhPU2V0", + "T3ZlcnJpZGVOb3RpZmljYXRpb25NZXNzYWdlIjgKNlN0b3BOb3RpZnlpbmdQ", + "cnVuaW5nUG9pbnRVVFhPU2V0T3ZlcnJpZGVSZXF1ZXN0TWVzc2FnZSJeCjdT", + "dG9wTm90aWZ5aW5nUHJ1bmluZ1BvaW50VVRYT1NldE92ZXJyaWRlUmVzcG9u", + "c2VNZXNzYWdlEiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJv", + "ciIfChFCYW5SZXF1ZXN0TWVzc2FnZRIKCgJpcBgBIAEoCSI5ChJCYW5SZXNw", + "b25zZU1lc3NhZ2USIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJlLlJQQ0Vy", + "cm9yIiEKE1VuYmFuUmVxdWVzdE1lc3NhZ2USCgoCaXAYASABKAkiOwoUVW5i", + "YW5SZXNwb25zZU1lc3NhZ2USIwoFZXJyb3IY6AcgASgLMhMucHJvdG93aXJl", + "LlJQQ0Vycm9yIhcKFUdldEluZm9SZXF1ZXN0TWVzc2FnZSKhAQoWR2V0SW5m", + "b1Jlc3BvbnNlTWVzc2FnZRINCgVwMnBJZBgBIAEoCRITCgttZW1wb29sU2l6", + "ZRgCIAEoBBIVCg1zZXJ2ZXJWZXJzaW9uGAMgASgJEhUKDWlzVXR4b0luZGV4", + "ZWQYBCABKAgSEAoIaXNTeW5jZWQYBSABKAgSIwoFZXJyb3IY6AcgASgLMhMu", + "cHJvdG93aXJlLlJQQ0Vycm9yIlUKLEVzdGltYXRlTmV0d29ya0hhc2hlc1Bl", + "clNlY29uZFJlcXVlc3RNZXNzYWdlEhIKCndpbmRvd1NpemUYASABKA0SEQoJ", + "c3RhcnRIYXNoGAIgASgJInQKLUVzdGltYXRlTmV0d29ya0hhc2hlc1BlclNl", + "Y29uZFJlc3BvbnNlTWVzc2FnZRIeChZuZXR3b3JrSGFzaGVzUGVyU2Vjb25k", + "GAEgASgEEiMKBWVycm9yGOgHIAEoCzITLnByb3Rvd2lyZS5SUENFcnJvciIm", + "CiROb3RpZnlOZXdCbG9ja1RlbXBsYXRlUmVxdWVzdE1lc3NhZ2UiTAolTm90", + "aWZ5TmV3QmxvY2tUZW1wbGF0ZVJlc3BvbnNlTWVzc2FnZRIjCgVlcnJvchjo", + "ByABKAsyEy5wcm90b3dpcmUuUlBDRXJyb3IiJQojTmV3QmxvY2tUZW1wbGF0", + "ZU5vdGlmaWNhdGlvbk1lc3NhZ2UifgoVTWVtcG9vbEVudHJ5QnlBZGRyZXNz", + "Eg8KB2FkZHJlc3MYASABKAkSKAoHc2VuZGluZxgCIAMoCzIXLnByb3Rvd2ly", + "ZS5NZW1wb29sRW50cnkSKgoJcmVjZWl2aW5nGAMgAygLMhcucHJvdG93aXJl", + "Lk1lbXBvb2xFbnRyeSJ5CipHZXRNZW1wb29sRW50cmllc0J5QWRkcmVzc2Vz", + "UmVxdWVzdE1lc3NhZ2USEQoJYWRkcmVzc2VzGAEgAygJEhkKEWluY2x1ZGVP", + "cnBoYW5Qb29sGAIgASgIEh0KFWZpbHRlclRyYW5zYWN0aW9uUG9vbBgDIAEo", + "CCKFAQorR2V0TWVtcG9vbEVudHJpZXNCeUFkZHJlc3Nlc1Jlc3BvbnNlTWVz", + "c2FnZRIxCgdlbnRyaWVzGAEgAygLMiAucHJvdG93aXJlLk1lbXBvb2xFbnRy", + "eUJ5QWRkcmVzcxIjCgVlcnJvchjoByABKAsyEy5wcm90b3dpcmUuUlBDRXJy", + "b3IiHQobR2V0Q29pblN1cHBseVJlcXVlc3RNZXNzYWdlIm8KHEdldENvaW5T", + "dXBwbHlSZXNwb25zZU1lc3NhZ2USEAoIbWF4U29tcGkYASABKAQSGAoQY2ly", + "Y3VsYXRpbmdTb21waRgCIAEoBBIjCgVlcnJvchjoByABKAsyEy5wcm90b3dp", + "cmUuUlBDRXJyb3JCJaoCIk1pbmluZ2NvcmUuQmxvY2tjaGFpbi5LYXNwYS5L", + "YXNwYWRiBnByb3RvMw==")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError), global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError.Parser, new[]{ "Message" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock.Parser, new[]{ "Header", "Transactions", "VerboseData" }, null, null, null, null), + 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.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), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint.Parser, new[]{ "TransactionId", "Index" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcUtxoEntry), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcUtxoEntry.Parser, new[]{ "Amount", "ScriptPublicKey", "BlockDaaScore", "IsCoinbase" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionVerboseData), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionVerboseData.Parser, new[]{ "TransactionId", "Hash", "Mass", "BlockHash", "BlockTime" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInputVerboseData), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInputVerboseData.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutputVerboseData), global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutputVerboseData.Parser, new[]{ "ScriptPublicKeyType", "ScriptPublicKeyAddress" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetCurrentNetworkResponseMessage.Parser, new[]{ "CurrentNetwork", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockRequestMessage.Parser, new[]{ "Block", "AllowNonDAABlocks" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Parser, new[]{ "RejectReason", "Error" }, null, new[]{ typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason) }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateRequestMessage.Parser, new[]{ "PayAddress", "ExtraData" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockTemplateResponseMessage.Parser, new[]{ "Block", "IsSynced", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyBlockAddedResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BlockAddedNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.BlockAddedNotificationMessage.Parser, new[]{ "Block" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesResponseMessage.Parser, new[]{ "Addresses", "BannedAddresses", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesKnownAddressMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesKnownAddressMessage.Parser, new[]{ "Addr" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetSelectedTipHashResponseMessage.Parser, new[]{ "SelectedTipHash", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryRequestMessage.Parser, new[]{ "TxId", "IncludeOrphanPool", "FilterTransactionPool" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntryResponseMessage.Parser, new[]{ "Entry", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesRequestMessage.Parser, new[]{ "IncludeOrphanPool", "FilterTransactionPool" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesResponseMessage.Parser, new[]{ "Entries", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry), global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry.Parser, new[]{ "Fee", "Transaction", "IsOrphan" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoResponseMessage.Parser, new[]{ "Infos", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoMessage.Parser, new[]{ "Id", "Address", "LastPingDuration", "IsOutbound", "TimeOffset", "UserAgent", "AdvertisedProtocolVersion", "TimeConnected", "IsIbdPeer" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerRequestMessage.Parser, new[]{ "Address", "IsPermanent" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.AddPeerResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionRequestMessage.Parser, new[]{ "Transaction", "AllowOrphan" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitTransactionResponseMessage.Parser, new[]{ "TransactionId", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedRequestMessage.Parser, new[]{ "IncludeAcceptedTransactionIds" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentChainChangedResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentChainChangedNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentChainChangedNotificationMessage.Parser, new[]{ "RemovedChainBlockHashes", "AddedChainBlockHashes", "AcceptedTransactionIds" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockRequestMessage.Parser, new[]{ "Hash", "IncludeTransactions" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockResponseMessage.Parser, new[]{ "Block", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkRequestMessage.Parser, new[]{ "SubnetworkId" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetSubnetworkResponseMessage.Parser, new[]{ "GasLimit", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockRequestMessage.Parser, new[]{ "StartHash", "IncludeAcceptedTransactionIds" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.AcceptedTransactionIds), global::Miningcore.Blockchain.Kaspa.Kaspad.AcceptedTransactionIds.Parser, new[]{ "AcceptingBlockHash", "AcceptedTransactionIds_" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentChainFromBlockResponseMessage.Parser, new[]{ "RemovedChainBlockHashes", "AddedChainBlockHashes", "AcceptedTransactionIds", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksRequestMessage.Parser, new[]{ "LowHash", "IncludeBlocks", "IncludeTransactions" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlocksResponseMessage.Parser, new[]{ "BlockHashes", "Blocks", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockCountResponseMessage.Parser, new[]{ "BlockCount", "HeaderCount", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBlockDagInfoResponseMessage.Parser, new[]{ "NetworkName", "BlockCount", "HeaderCount", "TipHashes", "Difficulty", "PastMedianTime", "VirtualParentHashes", "PruningPointHash", "VirtualDaaScore", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictRequestMessage.Parser, new[]{ "FinalityBlockHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.ResolveFinalityConflictResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyFinalityConflictsResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictNotificationMessage.Parser, new[]{ "ViolatingBlockHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictResolvedNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.FinalityConflictResolvedNotificationMessage.Parser, new[]{ "FinalityBlockHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.ShutDownResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersRequestMessage.Parser, new[]{ "StartHash", "Limit", "IsAscending" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetHeadersResponseMessage.Parser, new[]{ "Headers", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedRequestMessage.Parser, new[]{ "Addresses" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyUtxosChangedResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosChangedNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosChangedNotificationMessage.Parser, new[]{ "Added", "Removed" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosByAddressesEntry), global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosByAddressesEntry.Parser, new[]{ "Address", "Outpoint", "UtxoEntry" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedRequestMessage.Parser, new[]{ "Addresses" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingUtxosChangedResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesRequestMessage.Parser, new[]{ "Addresses" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetUtxosByAddressesResponseMessage.Parser, new[]{ "Entries", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressRequestMessage.Parser, new[]{ "Address" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalanceByAddressResponseMessage.Parser, new[]{ "Balance", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesRequestMessage.Parser, new[]{ "Addresses" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BalancesByAddressEntry), global::Miningcore.Blockchain.Kaspa.Kaspad.BalancesByAddressEntry.Parser, new[]{ "Address", "Balance", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetBalancesByAddressesResponseMessage.Parser, new[]{ "Entries", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetVirtualSelectedParentBlueScoreResponseMessage.Parser, new[]{ "BlueScore", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualSelectedParentBlueScoreChangedResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentBlueScoreChangedNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualSelectedParentBlueScoreChangedNotificationMessage.Parser, new[]{ "VirtualSelectedParentBlueScore" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyVirtualDaaScoreChangedResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualDaaScoreChangedNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.VirtualDaaScoreChangedNotificationMessage.Parser, new[]{ "VirtualDaaScore" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyPruningPointUTXOSetOverrideResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUTXOSetOverrideNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.PruningPointUTXOSetOverrideNotificationMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.StopNotifyingPruningPointUTXOSetOverrideResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BanRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.BanRequestMessage.Parser, new[]{ "Ip" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.BanResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.BanResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanRequestMessage.Parser, new[]{ "Ip" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.UnbanResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetInfoResponseMessage.Parser, new[]{ "P2PId", "MempoolSize", "ServerVersion", "IsUtxoIndexed", "IsSynced", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondRequestMessage.Parser, new[]{ "WindowSize", "StartHash" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.EstimateNetworkHashesPerSecondResponseMessage.Parser, new[]{ "NetworkHashesPerSecond", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NotifyNewBlockTemplateResponseMessage.Parser, new[]{ "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.NewBlockTemplateNotificationMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.NewBlockTemplateNotificationMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntryByAddress), global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntryByAddress.Parser, new[]{ "Address", "Sending", "Receiving" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesRequestMessage.Parser, new[]{ "Addresses", "IncludeOrphanPool", "FilterTransactionPool" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetMempoolEntriesByAddressesResponseMessage.Parser, new[]{ "Entries", "Error" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyRequestMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyRequestMessage.Parser, null, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyResponseMessage), global::Miningcore.Blockchain.Kaspa.Kaspad.GetCoinSupplyResponseMessage.Parser, new[]{ "MaxSompi", "CirculatingSompi", "Error" }, null, null, null, null) + })); + } + #endregion + + } + #region Messages + /// + /// RPCError represents a generic non-internal error. + /// + /// Receivers of any ResponseMessage are expected to check whether its error field is not null. + /// + public sealed partial class RPCError : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RPCError()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RPCError() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RPCError(RPCError other) : this() { + message_ = other.message_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RPCError Clone() { + return new RPCError(this); + } + + /// Field number for the "message" field. + public const int MessageFieldNumber = 1; + private string message_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Message { + get { return message_; } + set { + message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RPCError); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RPCError other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Message != other.Message) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Message.Length != 0) hash ^= Message.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 (Message.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Message); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Message.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RPCError other) { + if (other == null) { + return; + } + if (other.Message.Length != 0) { + Message = other.Message; + } + _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: { + Message = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RpcBlock : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcBlock()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlock() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlock(RpcBlock other) : this() { + header_ = other.header_ != null ? other.header_.Clone() : null; + transactions_ = other.transactions_.Clone(); + verboseData_ = other.verboseData_ != null ? other.verboseData_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlock Clone() { + return new RpcBlock(this); + } + + /// Field number for the "header" field. + public const int HeaderFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockHeader header_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockHeader Header { + get { return header_; } + set { + header_ = value; + } + } + + /// Field number for the "transactions" field. + public const int TransactionsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_transactions_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction.Parser); + private readonly pbc::RepeatedField transactions_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Transactions { + get { return transactions_; } + } + + /// Field number for the "verboseData" field. + public const int VerboseDataFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockVerboseData verboseData_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockVerboseData VerboseData { + get { return verboseData_; } + set { + verboseData_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcBlock); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcBlock other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Header, other.Header)) return false; + if(!transactions_.Equals(other.transactions_)) return false; + if (!object.Equals(VerboseData, other.VerboseData)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (header_ != null) hash ^= Header.GetHashCode(); + hash ^= transactions_.GetHashCode(); + if (verboseData_ != null) hash ^= VerboseData.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 (header_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Header); + } + transactions_.WriteTo(output, _repeated_transactions_codec); + if (verboseData_ != null) { + output.WriteRawTag(26); + output.WriteMessage(VerboseData); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (header_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Header); + } + size += transactions_.CalculateSize(_repeated_transactions_codec); + if (verboseData_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(VerboseData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcBlock other) { + if (other == null) { + return; + } + if (other.header_ != null) { + if (header_ == null) { + Header = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockHeader(); + } + Header.MergeFrom(other.Header); + } + transactions_.Add(other.transactions_); + if (other.verboseData_ != null) { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockVerboseData(); + } + VerboseData.MergeFrom(other.VerboseData); + } + _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: { + if (header_ == null) { + Header = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockHeader(); + } + input.ReadMessage(Header); + break; + } + case 18: { + transactions_.AddEntriesFrom(input, _repeated_transactions_codec); + break; + } + case 26: { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockVerboseData(); + } + input.ReadMessage(VerboseData); + break; + } + } + } + } + + } + + public sealed partial class RpcBlockHeader : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcBlockHeader()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[2]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockHeader() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockHeader(RpcBlockHeader other) : this() { + version_ = other.version_; + parents_ = other.parents_.Clone(); + hashMerkleRoot_ = other.hashMerkleRoot_; + acceptedIdMerkleRoot_ = other.acceptedIdMerkleRoot_; + utxoCommitment_ = other.utxoCommitment_; + timestamp_ = other.timestamp_; + bits_ = other.bits_; + nonce_ = other.nonce_; + daaScore_ = other.daaScore_; + blueWork_ = other.blueWork_; + pruningPoint_ = other.pruningPoint_; + blueScore_ = other.blueScore_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockHeader Clone() { + return new RpcBlockHeader(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private uint version_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Version { + get { return version_; } + set { + version_ = value; + } + } + + /// Field number for the "parents" field. + public const int ParentsFieldNumber = 12; + private static readonly pb::FieldCodec _repeated_parents_codec + = pb::FieldCodec.ForMessage(98, global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlockLevelParents.Parser); + private readonly pbc::RepeatedField parents_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Parents { + get { return parents_; } + } + + /// Field number for the "hashMerkleRoot" field. + public const int HashMerkleRootFieldNumber = 3; + private string hashMerkleRoot_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string HashMerkleRoot { + get { return hashMerkleRoot_; } + set { + hashMerkleRoot_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "acceptedIdMerkleRoot" field. + public const int AcceptedIdMerkleRootFieldNumber = 4; + private string acceptedIdMerkleRoot_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AcceptedIdMerkleRoot { + get { return acceptedIdMerkleRoot_; } + set { + acceptedIdMerkleRoot_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "utxoCommitment" field. + public const int UtxoCommitmentFieldNumber = 5; + private string utxoCommitment_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UtxoCommitment { + get { return utxoCommitment_; } + set { + utxoCommitment_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "timestamp" field. + public const int TimestampFieldNumber = 6; + private long timestamp_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long Timestamp { + get { return timestamp_; } + set { + timestamp_ = value; + } + } + + /// Field number for the "bits" field. + public const int BitsFieldNumber = 7; + private uint bits_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Bits { + get { return bits_; } + set { + bits_ = value; + } + } + + /// Field number for the "nonce" field. + public const int NonceFieldNumber = 8; + private ulong nonce_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Nonce { + get { return nonce_; } + set { + nonce_ = value; + } + } + + /// Field number for the "daaScore" field. + public const int DaaScoreFieldNumber = 9; + private ulong daaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong DaaScore { + get { return daaScore_; } + set { + daaScore_ = value; + } + } + + /// Field number for the "blueWork" field. + public const int BlueWorkFieldNumber = 10; + private string blueWork_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BlueWork { + get { return blueWork_; } + set { + blueWork_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "pruningPoint" field. + public const int PruningPointFieldNumber = 14; + private string pruningPoint_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string PruningPoint { + get { return pruningPoint_; } + set { + pruningPoint_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "blueScore" field. + public const int BlueScoreFieldNumber = 13; + private ulong blueScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlueScore { + get { return blueScore_; } + set { + blueScore_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcBlockHeader); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcBlockHeader other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + if(!parents_.Equals(other.parents_)) return false; + if (HashMerkleRoot != other.HashMerkleRoot) return false; + if (AcceptedIdMerkleRoot != other.AcceptedIdMerkleRoot) return false; + if (UtxoCommitment != other.UtxoCommitment) return false; + if (Timestamp != other.Timestamp) return false; + if (Bits != other.Bits) return false; + if (Nonce != other.Nonce) return false; + if (DaaScore != other.DaaScore) return false; + if (BlueWork != other.BlueWork) return false; + if (PruningPoint != other.PruningPoint) return false; + if (BlueScore != other.BlueScore) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version != 0) hash ^= Version.GetHashCode(); + hash ^= parents_.GetHashCode(); + if (HashMerkleRoot.Length != 0) hash ^= HashMerkleRoot.GetHashCode(); + if (AcceptedIdMerkleRoot.Length != 0) hash ^= AcceptedIdMerkleRoot.GetHashCode(); + if (UtxoCommitment.Length != 0) hash ^= UtxoCommitment.GetHashCode(); + if (Timestamp != 0L) hash ^= Timestamp.GetHashCode(); + if (Bits != 0) hash ^= Bits.GetHashCode(); + if (Nonce != 0UL) hash ^= Nonce.GetHashCode(); + if (DaaScore != 0UL) hash ^= DaaScore.GetHashCode(); + if (BlueWork.Length != 0) hash ^= BlueWork.GetHashCode(); + if (PruningPoint.Length != 0) hash ^= PruningPoint.GetHashCode(); + if (BlueScore != 0UL) hash ^= BlueScore.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 != 0) { + output.WriteRawTag(8); + output.WriteUInt32(Version); + } + if (HashMerkleRoot.Length != 0) { + output.WriteRawTag(26); + output.WriteString(HashMerkleRoot); + } + if (AcceptedIdMerkleRoot.Length != 0) { + output.WriteRawTag(34); + output.WriteString(AcceptedIdMerkleRoot); + } + if (UtxoCommitment.Length != 0) { + output.WriteRawTag(42); + output.WriteString(UtxoCommitment); + } + if (Timestamp != 0L) { + output.WriteRawTag(48); + output.WriteInt64(Timestamp); + } + if (Bits != 0) { + output.WriteRawTag(56); + output.WriteUInt32(Bits); + } + if (Nonce != 0UL) { + output.WriteRawTag(64); + output.WriteUInt64(Nonce); + } + if (DaaScore != 0UL) { + output.WriteRawTag(72); + output.WriteUInt64(DaaScore); + } + if (BlueWork.Length != 0) { + output.WriteRawTag(82); + output.WriteString(BlueWork); + } + parents_.WriteTo(output, _repeated_parents_codec); + if (BlueScore != 0UL) { + output.WriteRawTag(104); + output.WriteUInt64(BlueScore); + } + if (PruningPoint.Length != 0) { + output.WriteRawTag(114); + output.WriteString(PruningPoint); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Version); + } + size += parents_.CalculateSize(_repeated_parents_codec); + if (HashMerkleRoot.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(HashMerkleRoot); + } + if (AcceptedIdMerkleRoot.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AcceptedIdMerkleRoot); + } + if (UtxoCommitment.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UtxoCommitment); + } + if (Timestamp != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Timestamp); + } + if (Bits != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Bits); + } + if (Nonce != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Nonce); + } + if (DaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(DaaScore); + } + if (BlueWork.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BlueWork); + } + if (PruningPoint.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(PruningPoint); + } + if (BlueScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlueScore); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcBlockHeader other) { + if (other == null) { + return; + } + if (other.Version != 0) { + Version = other.Version; + } + parents_.Add(other.parents_); + if (other.HashMerkleRoot.Length != 0) { + HashMerkleRoot = other.HashMerkleRoot; + } + if (other.AcceptedIdMerkleRoot.Length != 0) { + AcceptedIdMerkleRoot = other.AcceptedIdMerkleRoot; + } + if (other.UtxoCommitment.Length != 0) { + UtxoCommitment = other.UtxoCommitment; + } + if (other.Timestamp != 0L) { + Timestamp = other.Timestamp; + } + if (other.Bits != 0) { + Bits = other.Bits; + } + if (other.Nonce != 0UL) { + Nonce = other.Nonce; + } + if (other.DaaScore != 0UL) { + DaaScore = other.DaaScore; + } + if (other.BlueWork.Length != 0) { + BlueWork = other.BlueWork; + } + if (other.PruningPoint.Length != 0) { + PruningPoint = other.PruningPoint; + } + if (other.BlueScore != 0UL) { + BlueScore = other.BlueScore; + } + _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 8: { + Version = input.ReadUInt32(); + break; + } + case 26: { + HashMerkleRoot = input.ReadString(); + break; + } + case 34: { + AcceptedIdMerkleRoot = input.ReadString(); + break; + } + case 42: { + UtxoCommitment = input.ReadString(); + break; + } + case 48: { + Timestamp = input.ReadInt64(); + break; + } + case 56: { + Bits = input.ReadUInt32(); + break; + } + case 64: { + Nonce = input.ReadUInt64(); + break; + } + case 72: { + DaaScore = input.ReadUInt64(); + break; + } + case 82: { + BlueWork = input.ReadString(); + break; + } + case 98: { + parents_.AddEntriesFrom(input, _repeated_parents_codec); + break; + } + case 104: { + BlueScore = input.ReadUInt64(); + break; + } + case 114: { + PruningPoint = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RpcBlockLevelParents : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcBlockLevelParents()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[3]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockLevelParents() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockLevelParents(RpcBlockLevelParents other) : this() { + parentHashes_ = other.parentHashes_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockLevelParents Clone() { + return new RpcBlockLevelParents(this); + } + + /// Field number for the "parentHashes" field. + public const int ParentHashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_parentHashes_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField parentHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField ParentHashes { + get { return parentHashes_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcBlockLevelParents); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcBlockLevelParents other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!parentHashes_.Equals(other.parentHashes_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= parentHashes_.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) { + parentHashes_.WriteTo(output, _repeated_parentHashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += parentHashes_.CalculateSize(_repeated_parentHashes_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcBlockLevelParents other) { + if (other == null) { + return; + } + parentHashes_.Add(other.parentHashes_); + _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: { + parentHashes_.AddEntriesFrom(input, _repeated_parentHashes_codec); + break; + } + } + } + } + + } + + public sealed partial class RpcBlockVerboseData : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcBlockVerboseData()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[4]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockVerboseData() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockVerboseData(RpcBlockVerboseData other) : this() { + hash_ = other.hash_; + difficulty_ = other.difficulty_; + selectedParentHash_ = other.selectedParentHash_; + transactionIds_ = other.transactionIds_.Clone(); + isHeaderOnly_ = other.isHeaderOnly_; + blueScore_ = other.blueScore_; + childrenHashes_ = other.childrenHashes_.Clone(); + mergeSetBluesHashes_ = other.mergeSetBluesHashes_.Clone(); + mergeSetRedsHashes_ = other.mergeSetRedsHashes_.Clone(); + isChainBlock_ = other.isChainBlock_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcBlockVerboseData Clone() { + return new RpcBlockVerboseData(this); + } + + /// Field number for the "hash" field. + public const int HashFieldNumber = 1; + private string hash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Hash { + get { return hash_; } + set { + hash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "difficulty" field. + public const int DifficultyFieldNumber = 11; + private double difficulty_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public double Difficulty { + get { return difficulty_; } + set { + difficulty_ = value; + } + } + + /// Field number for the "selectedParentHash" field. + public const int SelectedParentHashFieldNumber = 13; + private string selectedParentHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SelectedParentHash { + get { return selectedParentHash_; } + set { + selectedParentHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "transactionIds" field. + public const int TransactionIdsFieldNumber = 14; + private static readonly pb::FieldCodec _repeated_transactionIds_codec + = pb::FieldCodec.ForString(114); + private readonly pbc::RepeatedField transactionIds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField TransactionIds { + get { return transactionIds_; } + } + + /// Field number for the "isHeaderOnly" field. + public const int IsHeaderOnlyFieldNumber = 15; + private bool isHeaderOnly_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsHeaderOnly { + get { return isHeaderOnly_; } + set { + isHeaderOnly_ = value; + } + } + + /// Field number for the "blueScore" field. + public const int BlueScoreFieldNumber = 16; + private ulong blueScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlueScore { + get { return blueScore_; } + set { + blueScore_ = value; + } + } + + /// Field number for the "childrenHashes" field. + public const int ChildrenHashesFieldNumber = 17; + private static readonly pb::FieldCodec _repeated_childrenHashes_codec + = pb::FieldCodec.ForString(138); + private readonly pbc::RepeatedField childrenHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField ChildrenHashes { + get { return childrenHashes_; } + } + + /// Field number for the "mergeSetBluesHashes" field. + public const int MergeSetBluesHashesFieldNumber = 18; + private static readonly pb::FieldCodec _repeated_mergeSetBluesHashes_codec + = pb::FieldCodec.ForString(146); + private readonly pbc::RepeatedField mergeSetBluesHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField MergeSetBluesHashes { + get { return mergeSetBluesHashes_; } + } + + /// Field number for the "mergeSetRedsHashes" field. + public const int MergeSetRedsHashesFieldNumber = 19; + private static readonly pb::FieldCodec _repeated_mergeSetRedsHashes_codec + = pb::FieldCodec.ForString(154); + private readonly pbc::RepeatedField mergeSetRedsHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField MergeSetRedsHashes { + get { return mergeSetRedsHashes_; } + } + + /// Field number for the "isChainBlock" field. + public const int IsChainBlockFieldNumber = 20; + private bool isChainBlock_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsChainBlock { + get { return isChainBlock_; } + set { + isChainBlock_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcBlockVerboseData); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcBlockVerboseData other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Hash != other.Hash) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(Difficulty, other.Difficulty)) return false; + if (SelectedParentHash != other.SelectedParentHash) return false; + if(!transactionIds_.Equals(other.transactionIds_)) return false; + if (IsHeaderOnly != other.IsHeaderOnly) return false; + if (BlueScore != other.BlueScore) return false; + if(!childrenHashes_.Equals(other.childrenHashes_)) return false; + if(!mergeSetBluesHashes_.Equals(other.mergeSetBluesHashes_)) return false; + if(!mergeSetRedsHashes_.Equals(other.mergeSetRedsHashes_)) return false; + if (IsChainBlock != other.IsChainBlock) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Hash.Length != 0) hash ^= Hash.GetHashCode(); + if (Difficulty != 0D) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(Difficulty); + if (SelectedParentHash.Length != 0) hash ^= SelectedParentHash.GetHashCode(); + hash ^= transactionIds_.GetHashCode(); + if (IsHeaderOnly != false) hash ^= IsHeaderOnly.GetHashCode(); + if (BlueScore != 0UL) hash ^= BlueScore.GetHashCode(); + hash ^= childrenHashes_.GetHashCode(); + hash ^= mergeSetBluesHashes_.GetHashCode(); + hash ^= mergeSetRedsHashes_.GetHashCode(); + if (IsChainBlock != false) hash ^= IsChainBlock.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 (Hash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Hash); + } + if (Difficulty != 0D) { + output.WriteRawTag(89); + output.WriteDouble(Difficulty); + } + if (SelectedParentHash.Length != 0) { + output.WriteRawTag(106); + output.WriteString(SelectedParentHash); + } + transactionIds_.WriteTo(output, _repeated_transactionIds_codec); + if (IsHeaderOnly != false) { + output.WriteRawTag(120); + output.WriteBool(IsHeaderOnly); + } + if (BlueScore != 0UL) { + output.WriteRawTag(128, 1); + output.WriteUInt64(BlueScore); + } + childrenHashes_.WriteTo(output, _repeated_childrenHashes_codec); + mergeSetBluesHashes_.WriteTo(output, _repeated_mergeSetBluesHashes_codec); + mergeSetRedsHashes_.WriteTo(output, _repeated_mergeSetRedsHashes_codec); + if (IsChainBlock != false) { + output.WriteRawTag(160, 1); + output.WriteBool(IsChainBlock); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Hash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Hash); + } + if (Difficulty != 0D) { + size += 1 + 8; + } + if (SelectedParentHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SelectedParentHash); + } + size += transactionIds_.CalculateSize(_repeated_transactionIds_codec); + if (IsHeaderOnly != false) { + size += 1 + 1; + } + if (BlueScore != 0UL) { + size += 2 + pb::CodedOutputStream.ComputeUInt64Size(BlueScore); + } + size += childrenHashes_.CalculateSize(_repeated_childrenHashes_codec); + size += mergeSetBluesHashes_.CalculateSize(_repeated_mergeSetBluesHashes_codec); + size += mergeSetRedsHashes_.CalculateSize(_repeated_mergeSetRedsHashes_codec); + if (IsChainBlock != false) { + size += 2 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcBlockVerboseData other) { + if (other == null) { + return; + } + if (other.Hash.Length != 0) { + Hash = other.Hash; + } + if (other.Difficulty != 0D) { + Difficulty = other.Difficulty; + } + if (other.SelectedParentHash.Length != 0) { + SelectedParentHash = other.SelectedParentHash; + } + transactionIds_.Add(other.transactionIds_); + if (other.IsHeaderOnly != false) { + IsHeaderOnly = other.IsHeaderOnly; + } + if (other.BlueScore != 0UL) { + BlueScore = other.BlueScore; + } + childrenHashes_.Add(other.childrenHashes_); + mergeSetBluesHashes_.Add(other.mergeSetBluesHashes_); + mergeSetRedsHashes_.Add(other.mergeSetRedsHashes_); + if (other.IsChainBlock != false) { + IsChainBlock = other.IsChainBlock; + } + _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: { + Hash = input.ReadString(); + break; + } + case 89: { + Difficulty = input.ReadDouble(); + break; + } + case 106: { + SelectedParentHash = input.ReadString(); + break; + } + case 114: { + transactionIds_.AddEntriesFrom(input, _repeated_transactionIds_codec); + break; + } + case 120: { + IsHeaderOnly = input.ReadBool(); + break; + } + case 128: { + BlueScore = input.ReadUInt64(); + break; + } + case 138: { + childrenHashes_.AddEntriesFrom(input, _repeated_childrenHashes_codec); + break; + } + case 146: { + mergeSetBluesHashes_.AddEntriesFrom(input, _repeated_mergeSetBluesHashes_codec); + break; + } + case 154: { + mergeSetRedsHashes_.AddEntriesFrom(input, _repeated_mergeSetRedsHashes_codec); + break; + } + case 160: { + IsChainBlock = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class RpcTransaction : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcTransaction()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[5]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransaction() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransaction(RpcTransaction other) : this() { + version_ = other.version_; + inputs_ = other.inputs_.Clone(); + outputs_ = other.outputs_.Clone(); + lockTime_ = other.lockTime_; + subnetworkId_ = other.subnetworkId_; + gas_ = other.gas_; + payload_ = other.payload_; + verboseData_ = other.verboseData_ != null ? other.verboseData_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransaction Clone() { + return new RpcTransaction(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private uint version_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Version { + get { return version_; } + set { + version_ = value; + } + } + + /// Field number for the "inputs" field. + public const int InputsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_inputs_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInput.Parser); + private readonly pbc::RepeatedField inputs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Inputs { + get { return inputs_; } + } + + /// Field number for the "outputs" field. + public const int OutputsFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_outputs_codec + = pb::FieldCodec.ForMessage(26, global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutput.Parser); + private readonly pbc::RepeatedField outputs_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Outputs { + get { return outputs_; } + } + + /// Field number for the "lockTime" field. + public const int LockTimeFieldNumber = 4; + private ulong lockTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong LockTime { + get { return lockTime_; } + set { + lockTime_ = value; + } + } + + /// Field number for the "subnetworkId" field. + public const int SubnetworkIdFieldNumber = 5; + private string subnetworkId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SubnetworkId { + get { return subnetworkId_; } + set { + subnetworkId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "gas" field. + public const int GasFieldNumber = 6; + private ulong gas_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Gas { + get { return gas_; } + set { + gas_ = value; + } + } + + /// Field number for the "payload" field. + public const int PayloadFieldNumber = 8; + private string payload_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Payload { + get { return payload_; } + set { + payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "verboseData" field. + public const int VerboseDataFieldNumber = 9; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionVerboseData verboseData_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionVerboseData VerboseData { + get { return verboseData_; } + set { + verboseData_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcTransaction); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcTransaction other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + if(!inputs_.Equals(other.inputs_)) return false; + if(!outputs_.Equals(other.outputs_)) return false; + if (LockTime != other.LockTime) return false; + if (SubnetworkId != other.SubnetworkId) return false; + if (Gas != other.Gas) return false; + if (Payload != other.Payload) return false; + if (!object.Equals(VerboseData, other.VerboseData)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version != 0) hash ^= Version.GetHashCode(); + hash ^= inputs_.GetHashCode(); + hash ^= outputs_.GetHashCode(); + if (LockTime != 0UL) hash ^= LockTime.GetHashCode(); + if (SubnetworkId.Length != 0) hash ^= SubnetworkId.GetHashCode(); + if (Gas != 0UL) hash ^= Gas.GetHashCode(); + if (Payload.Length != 0) hash ^= Payload.GetHashCode(); + if (verboseData_ != null) hash ^= VerboseData.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 != 0) { + output.WriteRawTag(8); + output.WriteUInt32(Version); + } + inputs_.WriteTo(output, _repeated_inputs_codec); + outputs_.WriteTo(output, _repeated_outputs_codec); + if (LockTime != 0UL) { + output.WriteRawTag(32); + output.WriteUInt64(LockTime); + } + if (SubnetworkId.Length != 0) { + output.WriteRawTag(42); + output.WriteString(SubnetworkId); + } + if (Gas != 0UL) { + output.WriteRawTag(48); + output.WriteUInt64(Gas); + } + if (Payload.Length != 0) { + output.WriteRawTag(66); + output.WriteString(Payload); + } + if (verboseData_ != null) { + output.WriteRawTag(74); + output.WriteMessage(VerboseData); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Version); + } + size += inputs_.CalculateSize(_repeated_inputs_codec); + size += outputs_.CalculateSize(_repeated_outputs_codec); + if (LockTime != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(LockTime); + } + if (SubnetworkId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SubnetworkId); + } + if (Gas != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Gas); + } + if (Payload.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Payload); + } + if (verboseData_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(VerboseData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcTransaction other) { + if (other == null) { + return; + } + if (other.Version != 0) { + Version = other.Version; + } + inputs_.Add(other.inputs_); + outputs_.Add(other.outputs_); + if (other.LockTime != 0UL) { + LockTime = other.LockTime; + } + if (other.SubnetworkId.Length != 0) { + SubnetworkId = other.SubnetworkId; + } + if (other.Gas != 0UL) { + Gas = other.Gas; + } + if (other.Payload.Length != 0) { + Payload = other.Payload; + } + if (other.verboseData_ != null) { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionVerboseData(); + } + VerboseData.MergeFrom(other.VerboseData); + } + _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 8: { + Version = input.ReadUInt32(); + break; + } + case 18: { + inputs_.AddEntriesFrom(input, _repeated_inputs_codec); + break; + } + case 26: { + outputs_.AddEntriesFrom(input, _repeated_outputs_codec); + break; + } + case 32: { + LockTime = input.ReadUInt64(); + break; + } + case 42: { + SubnetworkId = input.ReadString(); + break; + } + case 48: { + Gas = input.ReadUInt64(); + break; + } + case 66: { + Payload = input.ReadString(); + break; + } + case 74: { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionVerboseData(); + } + input.ReadMessage(VerboseData); + break; + } + } + } + } + + } + + public sealed partial class RpcTransactionInput : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcTransactionInput()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[6]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionInput() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionInput(RpcTransactionInput other) : this() { + previousOutpoint_ = other.previousOutpoint_ != null ? other.previousOutpoint_.Clone() : null; + signatureScript_ = other.signatureScript_; + sequence_ = other.sequence_; + sigOpCount_ = other.sigOpCount_; + verboseData_ = other.verboseData_ != null ? other.verboseData_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionInput Clone() { + return new RpcTransactionInput(this); + } + + /// Field number for the "previousOutpoint" field. + public const int PreviousOutpointFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint previousOutpoint_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint PreviousOutpoint { + get { return previousOutpoint_; } + set { + previousOutpoint_ = value; + } + } + + /// Field number for the "signatureScript" field. + public const int SignatureScriptFieldNumber = 2; + private string signatureScript_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SignatureScript { + get { return signatureScript_; } + set { + signatureScript_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "sequence" field. + public const int SequenceFieldNumber = 3; + private ulong sequence_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Sequence { + get { return sequence_; } + set { + sequence_ = value; + } + } + + /// Field number for the "sigOpCount" field. + public const int SigOpCountFieldNumber = 5; + private uint sigOpCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint SigOpCount { + get { return sigOpCount_; } + set { + sigOpCount_ = value; + } + } + + /// Field number for the "verboseData" field. + public const int VerboseDataFieldNumber = 4; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInputVerboseData verboseData_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInputVerboseData VerboseData { + get { return verboseData_; } + set { + verboseData_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcTransactionInput); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcTransactionInput other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(PreviousOutpoint, other.PreviousOutpoint)) return false; + if (SignatureScript != other.SignatureScript) return false; + if (Sequence != other.Sequence) return false; + if (SigOpCount != other.SigOpCount) return false; + if (!object.Equals(VerboseData, other.VerboseData)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (previousOutpoint_ != null) hash ^= PreviousOutpoint.GetHashCode(); + if (SignatureScript.Length != 0) hash ^= SignatureScript.GetHashCode(); + if (Sequence != 0UL) hash ^= Sequence.GetHashCode(); + if (SigOpCount != 0) hash ^= SigOpCount.GetHashCode(); + if (verboseData_ != null) hash ^= VerboseData.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 (previousOutpoint_ != null) { + output.WriteRawTag(10); + output.WriteMessage(PreviousOutpoint); + } + if (SignatureScript.Length != 0) { + output.WriteRawTag(18); + output.WriteString(SignatureScript); + } + if (Sequence != 0UL) { + output.WriteRawTag(24); + output.WriteUInt64(Sequence); + } + if (verboseData_ != null) { + output.WriteRawTag(34); + output.WriteMessage(VerboseData); + } + if (SigOpCount != 0) { + output.WriteRawTag(40); + output.WriteUInt32(SigOpCount); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (previousOutpoint_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(PreviousOutpoint); + } + if (SignatureScript.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SignatureScript); + } + if (Sequence != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Sequence); + } + if (SigOpCount != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(SigOpCount); + } + if (verboseData_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(VerboseData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcTransactionInput other) { + if (other == null) { + return; + } + if (other.previousOutpoint_ != null) { + if (previousOutpoint_ == null) { + PreviousOutpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint(); + } + PreviousOutpoint.MergeFrom(other.PreviousOutpoint); + } + if (other.SignatureScript.Length != 0) { + SignatureScript = other.SignatureScript; + } + if (other.Sequence != 0UL) { + Sequence = other.Sequence; + } + if (other.SigOpCount != 0) { + SigOpCount = other.SigOpCount; + } + if (other.verboseData_ != null) { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInputVerboseData(); + } + VerboseData.MergeFrom(other.VerboseData); + } + _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: { + if (previousOutpoint_ == null) { + PreviousOutpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint(); + } + input.ReadMessage(PreviousOutpoint); + break; + } + case 18: { + SignatureScript = input.ReadString(); + break; + } + case 24: { + Sequence = input.ReadUInt64(); + break; + } + case 34: { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionInputVerboseData(); + } + input.ReadMessage(VerboseData); + break; + } + case 40: { + SigOpCount = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class RpcScriptPublicKey : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcScriptPublicKey()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[7]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcScriptPublicKey() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcScriptPublicKey(RpcScriptPublicKey other) : this() { + version_ = other.version_; + scriptPublicKey_ = other.scriptPublicKey_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcScriptPublicKey Clone() { + return new RpcScriptPublicKey(this); + } + + /// Field number for the "version" field. + public const int VersionFieldNumber = 1; + private uint version_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Version { + get { return version_; } + set { + version_ = value; + } + } + + /// Field number for the "scriptPublicKey" field. + public const int ScriptPublicKeyFieldNumber = 2; + private string scriptPublicKey_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ScriptPublicKey { + get { return scriptPublicKey_; } + set { + scriptPublicKey_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcScriptPublicKey); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcScriptPublicKey other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Version != other.Version) return false; + if (ScriptPublicKey != other.ScriptPublicKey) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Version != 0) hash ^= Version.GetHashCode(); + if (ScriptPublicKey.Length != 0) hash ^= ScriptPublicKey.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 != 0) { + output.WriteRawTag(8); + output.WriteUInt32(Version); + } + if (ScriptPublicKey.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ScriptPublicKey); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Version != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Version); + } + if (ScriptPublicKey.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ScriptPublicKey); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcScriptPublicKey other) { + if (other == null) { + return; + } + if (other.Version != 0) { + Version = other.Version; + } + if (other.ScriptPublicKey.Length != 0) { + ScriptPublicKey = other.ScriptPublicKey; + } + _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 8: { + Version = input.ReadUInt32(); + break; + } + case 18: { + ScriptPublicKey = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class RpcTransactionOutput : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcTransactionOutput()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[8]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionOutput() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionOutput(RpcTransactionOutput other) : this() { + amount_ = other.amount_; + scriptPublicKey_ = other.scriptPublicKey_ != null ? other.scriptPublicKey_.Clone() : null; + verboseData_ = other.verboseData_ != null ? other.verboseData_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionOutput Clone() { + return new RpcTransactionOutput(this); + } + + /// Field number for the "amount" field. + public const int AmountFieldNumber = 1; + private ulong amount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Amount { + get { return amount_; } + set { + amount_ = value; + } + } + + /// Field number for the "scriptPublicKey" field. + public const int ScriptPublicKeyFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey scriptPublicKey_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey ScriptPublicKey { + get { return scriptPublicKey_; } + set { + scriptPublicKey_ = value; + } + } + + /// Field number for the "verboseData" field. + public const int VerboseDataFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutputVerboseData verboseData_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutputVerboseData VerboseData { + get { return verboseData_; } + set { + verboseData_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcTransactionOutput); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcTransactionOutput other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Amount != other.Amount) return false; + if (!object.Equals(ScriptPublicKey, other.ScriptPublicKey)) return false; + if (!object.Equals(VerboseData, other.VerboseData)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Amount != 0UL) hash ^= Amount.GetHashCode(); + if (scriptPublicKey_ != null) hash ^= ScriptPublicKey.GetHashCode(); + if (verboseData_ != null) hash ^= VerboseData.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 (Amount != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Amount); + } + if (scriptPublicKey_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ScriptPublicKey); + } + if (verboseData_ != null) { + output.WriteRawTag(26); + output.WriteMessage(VerboseData); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Amount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Amount); + } + if (scriptPublicKey_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ScriptPublicKey); + } + if (verboseData_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(VerboseData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcTransactionOutput other) { + if (other == null) { + return; + } + if (other.Amount != 0UL) { + Amount = other.Amount; + } + if (other.scriptPublicKey_ != null) { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey(); + } + ScriptPublicKey.MergeFrom(other.ScriptPublicKey); + } + if (other.verboseData_ != null) { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutputVerboseData(); + } + VerboseData.MergeFrom(other.VerboseData); + } + _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 8: { + Amount = input.ReadUInt64(); + break; + } + case 18: { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey(); + } + input.ReadMessage(ScriptPublicKey); + break; + } + case 26: { + if (verboseData_ == null) { + VerboseData = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransactionOutputVerboseData(); + } + input.ReadMessage(VerboseData); + break; + } + } + } + } + + } + + public sealed partial class RpcOutpoint : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcOutpoint()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[9]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcOutpoint() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcOutpoint(RpcOutpoint other) : this() { + transactionId_ = other.transactionId_; + index_ = other.index_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcOutpoint Clone() { + return new RpcOutpoint(this); + } + + /// Field number for the "transactionId" field. + public const int TransactionIdFieldNumber = 1; + private string transactionId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TransactionId { + get { return transactionId_; } + set { + transactionId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "index" field. + public const int IndexFieldNumber = 2; + private uint index_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint Index { + get { return index_; } + set { + index_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcOutpoint); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcOutpoint other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (TransactionId != other.TransactionId) return false; + if (Index != other.Index) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (TransactionId.Length != 0) hash ^= TransactionId.GetHashCode(); + if (Index != 0) hash ^= Index.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 (TransactionId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(TransactionId); + } + if (Index != 0) { + output.WriteRawTag(16); + output.WriteUInt32(Index); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (TransactionId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TransactionId); + } + if (Index != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Index); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcOutpoint other) { + if (other == null) { + return; + } + if (other.TransactionId.Length != 0) { + TransactionId = other.TransactionId; + } + if (other.Index != 0) { + Index = other.Index; + } + _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: { + TransactionId = input.ReadString(); + break; + } + case 16: { + Index = input.ReadUInt32(); + break; + } + } + } + } + + } + + public sealed partial class RpcUtxoEntry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcUtxoEntry()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[10]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcUtxoEntry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcUtxoEntry(RpcUtxoEntry other) : this() { + amount_ = other.amount_; + scriptPublicKey_ = other.scriptPublicKey_ != null ? other.scriptPublicKey_.Clone() : null; + blockDaaScore_ = other.blockDaaScore_; + isCoinbase_ = other.isCoinbase_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcUtxoEntry Clone() { + return new RpcUtxoEntry(this); + } + + /// Field number for the "amount" field. + public const int AmountFieldNumber = 1; + private ulong amount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Amount { + get { return amount_; } + set { + amount_ = value; + } + } + + /// Field number for the "scriptPublicKey" field. + public const int ScriptPublicKeyFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey scriptPublicKey_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey ScriptPublicKey { + get { return scriptPublicKey_; } + set { + scriptPublicKey_ = value; + } + } + + /// Field number for the "blockDaaScore" field. + public const int BlockDaaScoreFieldNumber = 3; + private ulong blockDaaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlockDaaScore { + get { return blockDaaScore_; } + set { + blockDaaScore_ = value; + } + } + + /// Field number for the "isCoinbase" field. + public const int IsCoinbaseFieldNumber = 4; + private bool isCoinbase_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsCoinbase { + get { return isCoinbase_; } + set { + isCoinbase_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcUtxoEntry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcUtxoEntry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Amount != other.Amount) return false; + if (!object.Equals(ScriptPublicKey, other.ScriptPublicKey)) return false; + if (BlockDaaScore != other.BlockDaaScore) return false; + if (IsCoinbase != other.IsCoinbase) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Amount != 0UL) hash ^= Amount.GetHashCode(); + if (scriptPublicKey_ != null) hash ^= ScriptPublicKey.GetHashCode(); + if (BlockDaaScore != 0UL) hash ^= BlockDaaScore.GetHashCode(); + if (IsCoinbase != false) hash ^= IsCoinbase.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 (Amount != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Amount); + } + if (scriptPublicKey_ != null) { + output.WriteRawTag(18); + output.WriteMessage(ScriptPublicKey); + } + if (BlockDaaScore != 0UL) { + output.WriteRawTag(24); + output.WriteUInt64(BlockDaaScore); + } + if (IsCoinbase != false) { + output.WriteRawTag(32); + output.WriteBool(IsCoinbase); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Amount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Amount); + } + if (scriptPublicKey_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(ScriptPublicKey); + } + if (BlockDaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlockDaaScore); + } + if (IsCoinbase != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcUtxoEntry other) { + if (other == null) { + return; + } + if (other.Amount != 0UL) { + Amount = other.Amount; + } + if (other.scriptPublicKey_ != null) { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey(); + } + ScriptPublicKey.MergeFrom(other.ScriptPublicKey); + } + if (other.BlockDaaScore != 0UL) { + BlockDaaScore = other.BlockDaaScore; + } + if (other.IsCoinbase != false) { + IsCoinbase = other.IsCoinbase; + } + _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 8: { + Amount = input.ReadUInt64(); + break; + } + case 18: { + if (scriptPublicKey_ == null) { + ScriptPublicKey = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcScriptPublicKey(); + } + input.ReadMessage(ScriptPublicKey); + break; + } + case 24: { + BlockDaaScore = input.ReadUInt64(); + break; + } + case 32: { + IsCoinbase = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class RpcTransactionVerboseData : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcTransactionVerboseData()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[11]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionVerboseData() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionVerboseData(RpcTransactionVerboseData other) : this() { + transactionId_ = other.transactionId_; + hash_ = other.hash_; + mass_ = other.mass_; + blockHash_ = other.blockHash_; + blockTime_ = other.blockTime_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionVerboseData Clone() { + return new RpcTransactionVerboseData(this); + } + + /// Field number for the "transactionId" field. + public const int TransactionIdFieldNumber = 1; + private string transactionId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TransactionId { + get { return transactionId_; } + set { + transactionId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "hash" field. + public const int HashFieldNumber = 2; + private string hash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Hash { + get { return hash_; } + set { + hash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "mass" field. + public const int MassFieldNumber = 4; + private ulong mass_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Mass { + get { return mass_; } + set { + mass_ = value; + } + } + + /// Field number for the "blockHash" field. + public const int BlockHashFieldNumber = 12; + private string blockHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string BlockHash { + get { return blockHash_; } + set { + blockHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "blockTime" field. + public const int BlockTimeFieldNumber = 14; + private ulong blockTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlockTime { + get { return blockTime_; } + set { + blockTime_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcTransactionVerboseData); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcTransactionVerboseData other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (TransactionId != other.TransactionId) return false; + if (Hash != other.Hash) return false; + if (Mass != other.Mass) return false; + if (BlockHash != other.BlockHash) return false; + if (BlockTime != other.BlockTime) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (TransactionId.Length != 0) hash ^= TransactionId.GetHashCode(); + if (Hash.Length != 0) hash ^= Hash.GetHashCode(); + if (Mass != 0UL) hash ^= Mass.GetHashCode(); + if (BlockHash.Length != 0) hash ^= BlockHash.GetHashCode(); + if (BlockTime != 0UL) hash ^= BlockTime.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 (TransactionId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(TransactionId); + } + if (Hash.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Hash); + } + if (Mass != 0UL) { + output.WriteRawTag(32); + output.WriteUInt64(Mass); + } + if (BlockHash.Length != 0) { + output.WriteRawTag(98); + output.WriteString(BlockHash); + } + if (BlockTime != 0UL) { + output.WriteRawTag(112); + output.WriteUInt64(BlockTime); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (TransactionId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TransactionId); + } + if (Hash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Hash); + } + if (Mass != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Mass); + } + if (BlockHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(BlockHash); + } + if (BlockTime != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlockTime); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcTransactionVerboseData other) { + if (other == null) { + return; + } + if (other.TransactionId.Length != 0) { + TransactionId = other.TransactionId; + } + if (other.Hash.Length != 0) { + Hash = other.Hash; + } + if (other.Mass != 0UL) { + Mass = other.Mass; + } + if (other.BlockHash.Length != 0) { + BlockHash = other.BlockHash; + } + if (other.BlockTime != 0UL) { + BlockTime = other.BlockTime; + } + _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: { + TransactionId = input.ReadString(); + break; + } + case 18: { + Hash = input.ReadString(); + break; + } + case 32: { + Mass = input.ReadUInt64(); + break; + } + case 98: { + BlockHash = input.ReadString(); + break; + } + case 112: { + BlockTime = input.ReadUInt64(); + break; + } + } + } + } + + } + + public sealed partial class RpcTransactionInputVerboseData : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcTransactionInputVerboseData()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[12]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionInputVerboseData() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionInputVerboseData(RpcTransactionInputVerboseData other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionInputVerboseData Clone() { + return new RpcTransactionInputVerboseData(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcTransactionInputVerboseData); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcTransactionInputVerboseData 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(RpcTransactionInputVerboseData 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 RpcTransactionOutputVerboseData : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new RpcTransactionOutputVerboseData()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[13]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionOutputVerboseData() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionOutputVerboseData(RpcTransactionOutputVerboseData other) : this() { + scriptPublicKeyType_ = other.scriptPublicKeyType_; + scriptPublicKeyAddress_ = other.scriptPublicKeyAddress_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public RpcTransactionOutputVerboseData Clone() { + return new RpcTransactionOutputVerboseData(this); + } + + /// Field number for the "scriptPublicKeyType" field. + public const int ScriptPublicKeyTypeFieldNumber = 5; + private string scriptPublicKeyType_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ScriptPublicKeyType { + get { return scriptPublicKeyType_; } + set { + scriptPublicKeyType_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "scriptPublicKeyAddress" field. + public const int ScriptPublicKeyAddressFieldNumber = 6; + private string scriptPublicKeyAddress_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ScriptPublicKeyAddress { + get { return scriptPublicKeyAddress_; } + set { + scriptPublicKeyAddress_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as RpcTransactionOutputVerboseData); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(RpcTransactionOutputVerboseData other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ScriptPublicKeyType != other.ScriptPublicKeyType) return false; + if (ScriptPublicKeyAddress != other.ScriptPublicKeyAddress) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ScriptPublicKeyType.Length != 0) hash ^= ScriptPublicKeyType.GetHashCode(); + if (ScriptPublicKeyAddress.Length != 0) hash ^= ScriptPublicKeyAddress.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 (ScriptPublicKeyType.Length != 0) { + output.WriteRawTag(42); + output.WriteString(ScriptPublicKeyType); + } + if (ScriptPublicKeyAddress.Length != 0) { + output.WriteRawTag(50); + output.WriteString(ScriptPublicKeyAddress); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ScriptPublicKeyType.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ScriptPublicKeyType); + } + if (ScriptPublicKeyAddress.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ScriptPublicKeyAddress); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(RpcTransactionOutputVerboseData other) { + if (other == null) { + return; + } + if (other.ScriptPublicKeyType.Length != 0) { + ScriptPublicKeyType = other.ScriptPublicKeyType; + } + if (other.ScriptPublicKeyAddress.Length != 0) { + ScriptPublicKeyAddress = other.ScriptPublicKeyAddress; + } + _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 42: { + ScriptPublicKeyType = input.ReadString(); + break; + } + case 50: { + ScriptPublicKeyAddress = input.ReadString(); + break; + } + } + } + } + + } + + /// + /// GetCurrentNetworkRequestMessage requests the network kaspad is currently running against. + /// + /// Possible networks are: Mainnet, Testnet, Simnet, Devnet + /// + public sealed partial class GetCurrentNetworkRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetCurrentNetworkRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[14]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCurrentNetworkRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCurrentNetworkRequestMessage(GetCurrentNetworkRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCurrentNetworkRequestMessage Clone() { + return new GetCurrentNetworkRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetCurrentNetworkRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetCurrentNetworkRequestMessage 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(GetCurrentNetworkRequestMessage 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 GetCurrentNetworkResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetCurrentNetworkResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[15]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCurrentNetworkResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCurrentNetworkResponseMessage(GetCurrentNetworkResponseMessage other) : this() { + currentNetwork_ = other.currentNetwork_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCurrentNetworkResponseMessage Clone() { + return new GetCurrentNetworkResponseMessage(this); + } + + /// Field number for the "currentNetwork" field. + public const int CurrentNetworkFieldNumber = 1; + private string currentNetwork_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string CurrentNetwork { + get { return currentNetwork_; } + set { + currentNetwork_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetCurrentNetworkResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetCurrentNetworkResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (CurrentNetwork != other.CurrentNetwork) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (CurrentNetwork.Length != 0) hash ^= CurrentNetwork.GetHashCode(); + if (error_ != null) hash ^= Error.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 (CurrentNetwork.Length != 0) { + output.WriteRawTag(10); + output.WriteString(CurrentNetwork); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (CurrentNetwork.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(CurrentNetwork); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetCurrentNetworkResponseMessage other) { + if (other == null) { + return; + } + if (other.CurrentNetwork.Length != 0) { + CurrentNetwork = other.CurrentNetwork; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + CurrentNetwork = input.ReadString(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// SubmitBlockRequestMessage requests to submit a block into the DAG. + /// Blocks are generally expected to have been generated using the getBlockTemplate call. + /// + /// See: GetBlockTemplateRequestMessage + /// + public sealed partial class SubmitBlockRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SubmitBlockRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[16]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitBlockRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitBlockRequestMessage(SubmitBlockRequestMessage other) : this() { + block_ = other.block_ != null ? other.block_.Clone() : null; + allowNonDAABlocks_ = other.allowNonDAABlocks_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitBlockRequestMessage Clone() { + return new SubmitBlockRequestMessage(this); + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock block_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock Block { + get { return block_; } + set { + block_ = value; + } + } + + /// Field number for the "allowNonDAABlocks" field. + public const int AllowNonDAABlocksFieldNumber = 3; + private bool allowNonDAABlocks_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool AllowNonDAABlocks { + get { return allowNonDAABlocks_; } + set { + allowNonDAABlocks_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SubmitBlockRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SubmitBlockRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Block, other.Block)) return false; + if (AllowNonDAABlocks != other.AllowNonDAABlocks) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (block_ != null) hash ^= Block.GetHashCode(); + if (AllowNonDAABlocks != false) hash ^= AllowNonDAABlocks.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 (block_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Block); + } + if (AllowNonDAABlocks != false) { + output.WriteRawTag(24); + output.WriteBool(AllowNonDAABlocks); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (block_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + if (AllowNonDAABlocks != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SubmitBlockRequestMessage other) { + if (other == null) { + return; + } + if (other.block_ != null) { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + Block.MergeFrom(other.Block); + } + if (other.AllowNonDAABlocks != false) { + AllowNonDAABlocks = other.AllowNonDAABlocks; + } + _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 18: { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + input.ReadMessage(Block); + break; + } + case 24: { + AllowNonDAABlocks = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class SubmitBlockResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SubmitBlockResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[17]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitBlockResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitBlockResponseMessage(SubmitBlockResponseMessage other) : this() { + rejectReason_ = other.rejectReason_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitBlockResponseMessage Clone() { + return new SubmitBlockResponseMessage(this); + } + + /// Field number for the "rejectReason" field. + public const int RejectReasonFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason rejectReason_ = global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason.None; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason RejectReason { + get { return rejectReason_; } + set { + rejectReason_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SubmitBlockResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SubmitBlockResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (RejectReason != other.RejectReason) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (RejectReason != global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason.None) hash ^= RejectReason.GetHashCode(); + if (error_ != null) hash ^= Error.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 (RejectReason != global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason.None) { + output.WriteRawTag(8); + output.WriteEnum((int) RejectReason); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (RejectReason != global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason.None) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RejectReason); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SubmitBlockResponseMessage other) { + if (other == null) { + return; + } + if (other.RejectReason != global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason.None) { + RejectReason = other.RejectReason; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8: { + RejectReason = (global::Miningcore.Blockchain.Kaspa.Kaspad.SubmitBlockResponseMessage.Types.RejectReason) input.ReadEnum(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + #region Nested types + /// Container for nested types declared in the SubmitBlockResponseMessage message type. + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static partial class Types { + public enum RejectReason { + [pbr::OriginalName("NONE")] None = 0, + [pbr::OriginalName("BLOCK_INVALID")] BlockInvalid = 1, + [pbr::OriginalName("IS_IN_IBD")] IsInIbd = 2, + } + + } + #endregion + + } + + /// + /// GetBlockTemplateRequestMessage requests a current block template. + /// Callers are expected to solve the block template and submit it using the submitBlock call + /// + /// See: SubmitBlockRequestMessage + /// + public sealed partial class GetBlockTemplateRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockTemplateRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[18]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockTemplateRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockTemplateRequestMessage(GetBlockTemplateRequestMessage other) : this() { + payAddress_ = other.payAddress_; + extraData_ = other.extraData_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockTemplateRequestMessage Clone() { + return new GetBlockTemplateRequestMessage(this); + } + + /// Field number for the "payAddress" field. + public const int PayAddressFieldNumber = 1; + private string payAddress_ = ""; + /// + /// Which kaspa address should the coinbase block reward transaction pay into + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string PayAddress { + get { return payAddress_; } + set { + payAddress_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "extraData" field. + public const int ExtraDataFieldNumber = 2; + private string extraData_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ExtraData { + get { return extraData_; } + set { + extraData_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockTemplateRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockTemplateRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (PayAddress != other.PayAddress) return false; + if (ExtraData != other.ExtraData) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (PayAddress.Length != 0) hash ^= PayAddress.GetHashCode(); + if (ExtraData.Length != 0) hash ^= ExtraData.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 (PayAddress.Length != 0) { + output.WriteRawTag(10); + output.WriteString(PayAddress); + } + if (ExtraData.Length != 0) { + output.WriteRawTag(18); + output.WriteString(ExtraData); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (PayAddress.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(PayAddress); + } + if (ExtraData.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ExtraData); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlockTemplateRequestMessage other) { + if (other == null) { + return; + } + if (other.PayAddress.Length != 0) { + PayAddress = other.PayAddress; + } + if (other.ExtraData.Length != 0) { + ExtraData = other.ExtraData; + } + _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: { + PayAddress = input.ReadString(); + break; + } + case 18: { + ExtraData = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class GetBlockTemplateResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockTemplateResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[19]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockTemplateResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockTemplateResponseMessage(GetBlockTemplateResponseMessage other) : this() { + block_ = other.block_ != null ? other.block_.Clone() : null; + isSynced_ = other.isSynced_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockTemplateResponseMessage Clone() { + return new GetBlockTemplateResponseMessage(this); + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock block_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock Block { + get { return block_; } + set { + block_ = value; + } + } + + /// Field number for the "isSynced" field. + public const int IsSyncedFieldNumber = 2; + private bool isSynced_; + /// + /// Whether kaspad thinks that it's synced. + /// Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced. + /// That is because when kaspad isn't in sync with the rest of the network there's a high + /// chance the block will never be accepted, thus the solving effort would have been wasted. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsSynced { + get { return isSynced_; } + set { + isSynced_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockTemplateResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockTemplateResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Block, other.Block)) return false; + if (IsSynced != other.IsSynced) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (block_ != null) hash ^= Block.GetHashCode(); + if (IsSynced != false) hash ^= IsSynced.GetHashCode(); + if (error_ != null) hash ^= Error.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 (IsSynced != false) { + output.WriteRawTag(16); + output.WriteBool(IsSynced); + } + if (block_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Block); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (block_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + if (IsSynced != false) { + size += 1 + 1; + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlockTemplateResponseMessage other) { + if (other == null) { + return; + } + if (other.block_ != null) { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + Block.MergeFrom(other.Block); + } + if (other.IsSynced != false) { + IsSynced = other.IsSynced; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 16: { + IsSynced = input.ReadBool(); + break; + } + case 26: { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + input.ReadMessage(Block); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// NotifyBlockAddedRequestMessage registers this connection for blockAdded notifications. + /// + /// See: BlockAddedNotificationMessage + /// + public sealed partial class NotifyBlockAddedRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyBlockAddedRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[20]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyBlockAddedRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyBlockAddedRequestMessage(NotifyBlockAddedRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyBlockAddedRequestMessage Clone() { + return new NotifyBlockAddedRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyBlockAddedRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyBlockAddedRequestMessage 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(NotifyBlockAddedRequestMessage 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 NotifyBlockAddedResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyBlockAddedResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[21]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyBlockAddedResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyBlockAddedResponseMessage(NotifyBlockAddedResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyBlockAddedResponseMessage Clone() { + return new NotifyBlockAddedResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyBlockAddedResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyBlockAddedResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyBlockAddedResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// BlockAddedNotificationMessage is sent whenever a blocks has been added (NOT accepted) + /// into the DAG. + /// + /// See: NotifyBlockAddedRequestMessage + /// + public sealed partial class BlockAddedNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BlockAddedNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[22]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockAddedNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockAddedNotificationMessage(BlockAddedNotificationMessage other) : this() { + block_ = other.block_ != null ? other.block_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BlockAddedNotificationMessage Clone() { + return new BlockAddedNotificationMessage(this); + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock block_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock Block { + get { return block_; } + set { + block_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BlockAddedNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BlockAddedNotificationMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Block, other.Block)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (block_ != null) hash ^= Block.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 (block_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Block); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (block_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BlockAddedNotificationMessage other) { + if (other == null) { + return; + } + if (other.block_ != null) { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + Block.MergeFrom(other.Block); + } + _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 26: { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + input.ReadMessage(Block); + break; + } + } + } + } + + } + + /// + /// GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the + /// current network. (mainnet, testnet, etc.) + /// + public sealed partial class GetPeerAddressesRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetPeerAddressesRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[23]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesRequestMessage(GetPeerAddressesRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesRequestMessage Clone() { + return new GetPeerAddressesRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetPeerAddressesRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetPeerAddressesRequestMessage 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(GetPeerAddressesRequestMessage 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 GetPeerAddressesResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetPeerAddressesResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[24]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesResponseMessage(GetPeerAddressesResponseMessage other) : this() { + addresses_ = other.addresses_.Clone(); + bannedAddresses_ = other.bannedAddresses_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesResponseMessage Clone() { + return new GetPeerAddressesResponseMessage(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesKnownAddressMessage.Parser); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + /// Field number for the "bannedAddresses" field. + public const int BannedAddressesFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_bannedAddresses_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.GetPeerAddressesKnownAddressMessage.Parser); + private readonly pbc::RepeatedField bannedAddresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField BannedAddresses { + get { return bannedAddresses_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetPeerAddressesResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetPeerAddressesResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + if(!bannedAddresses_.Equals(other.bannedAddresses_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.GetHashCode(); + hash ^= bannedAddresses_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + addresses_.WriteTo(output, _repeated_addresses_codec); + bannedAddresses_.WriteTo(output, _repeated_bannedAddresses_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + size += bannedAddresses_.CalculateSize(_repeated_bannedAddresses_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetPeerAddressesResponseMessage other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + bannedAddresses_.Add(other.bannedAddresses_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + case 18: { + bannedAddresses_.AddEntriesFrom(input, _repeated_bannedAddresses_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class GetPeerAddressesKnownAddressMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetPeerAddressesKnownAddressMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[25]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesKnownAddressMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesKnownAddressMessage(GetPeerAddressesKnownAddressMessage other) : this() { + addr_ = other.addr_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetPeerAddressesKnownAddressMessage Clone() { + return new GetPeerAddressesKnownAddressMessage(this); + } + + /// Field number for the "Addr" field. + public const int AddrFieldNumber = 1; + private string addr_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Addr { + get { return addr_; } + set { + addr_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetPeerAddressesKnownAddressMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetPeerAddressesKnownAddressMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Addr != other.Addr) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Addr.Length != 0) hash ^= Addr.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 (Addr.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Addr); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Addr.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Addr); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetPeerAddressesKnownAddressMessage other) { + if (other == null) { + return; + } + if (other.Addr.Length != 0) { + Addr = other.Addr; + } + _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: { + Addr = input.ReadString(); + break; + } + } + } + } + + } + + /// + /// GetSelectedTipHashRequestMessage requests the hash of the current virtual's + /// selected parent. + /// + public sealed partial class GetSelectedTipHashRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetSelectedTipHashRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[26]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSelectedTipHashRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSelectedTipHashRequestMessage(GetSelectedTipHashRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSelectedTipHashRequestMessage Clone() { + return new GetSelectedTipHashRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetSelectedTipHashRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetSelectedTipHashRequestMessage 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(GetSelectedTipHashRequestMessage 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 GetSelectedTipHashResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetSelectedTipHashResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[27]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSelectedTipHashResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSelectedTipHashResponseMessage(GetSelectedTipHashResponseMessage other) : this() { + selectedTipHash_ = other.selectedTipHash_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSelectedTipHashResponseMessage Clone() { + return new GetSelectedTipHashResponseMessage(this); + } + + /// Field number for the "selectedTipHash" field. + public const int SelectedTipHashFieldNumber = 1; + private string selectedTipHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SelectedTipHash { + get { return selectedTipHash_; } + set { + selectedTipHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetSelectedTipHashResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetSelectedTipHashResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (SelectedTipHash != other.SelectedTipHash) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (SelectedTipHash.Length != 0) hash ^= SelectedTipHash.GetHashCode(); + if (error_ != null) hash ^= Error.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 (SelectedTipHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(SelectedTipHash); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (SelectedTipHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SelectedTipHash); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetSelectedTipHashResponseMessage other) { + if (other == null) { + return; + } + if (other.SelectedTipHash.Length != 0) { + SelectedTipHash = other.SelectedTipHash; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + SelectedTipHash = input.ReadString(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetMempoolEntryRequestMessage requests information about a specific transaction + /// in the mempool. + /// + public sealed partial class GetMempoolEntryRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMempoolEntryRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[28]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntryRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntryRequestMessage(GetMempoolEntryRequestMessage other) : this() { + txId_ = other.txId_; + includeOrphanPool_ = other.includeOrphanPool_; + filterTransactionPool_ = other.filterTransactionPool_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntryRequestMessage Clone() { + return new GetMempoolEntryRequestMessage(this); + } + + /// Field number for the "txId" field. + public const int TxIdFieldNumber = 1; + private string txId_ = ""; + /// + /// The transaction's TransactionID. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TxId { + get { return txId_; } + set { + txId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "includeOrphanPool" field. + public const int IncludeOrphanPoolFieldNumber = 2; + private bool includeOrphanPool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeOrphanPool { + get { return includeOrphanPool_; } + set { + includeOrphanPool_ = value; + } + } + + /// Field number for the "filterTransactionPool" field. + public const int FilterTransactionPoolFieldNumber = 3; + private bool filterTransactionPool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool FilterTransactionPool { + get { return filterTransactionPool_; } + set { + filterTransactionPool_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetMempoolEntryRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetMempoolEntryRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (TxId != other.TxId) return false; + if (IncludeOrphanPool != other.IncludeOrphanPool) return false; + if (FilterTransactionPool != other.FilterTransactionPool) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (TxId.Length != 0) hash ^= TxId.GetHashCode(); + if (IncludeOrphanPool != false) hash ^= IncludeOrphanPool.GetHashCode(); + if (FilterTransactionPool != false) hash ^= FilterTransactionPool.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 (TxId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(TxId); + } + if (IncludeOrphanPool != false) { + output.WriteRawTag(16); + output.WriteBool(IncludeOrphanPool); + } + if (FilterTransactionPool != false) { + output.WriteRawTag(24); + output.WriteBool(FilterTransactionPool); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (TxId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TxId); + } + if (IncludeOrphanPool != false) { + size += 1 + 1; + } + if (FilterTransactionPool != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetMempoolEntryRequestMessage other) { + if (other == null) { + return; + } + if (other.TxId.Length != 0) { + TxId = other.TxId; + } + if (other.IncludeOrphanPool != false) { + IncludeOrphanPool = other.IncludeOrphanPool; + } + if (other.FilterTransactionPool != false) { + FilterTransactionPool = other.FilterTransactionPool; + } + _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: { + TxId = input.ReadString(); + break; + } + case 16: { + IncludeOrphanPool = input.ReadBool(); + break; + } + case 24: { + FilterTransactionPool = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class GetMempoolEntryResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMempoolEntryResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[29]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntryResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntryResponseMessage(GetMempoolEntryResponseMessage other) : this() { + entry_ = other.entry_ != null ? other.entry_.Clone() : null; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntryResponseMessage Clone() { + return new GetMempoolEntryResponseMessage(this); + } + + /// Field number for the "entry" field. + public const int EntryFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry entry_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry Entry { + get { return entry_; } + set { + entry_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetMempoolEntryResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetMempoolEntryResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Entry, other.Entry)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (entry_ != null) hash ^= Entry.GetHashCode(); + if (error_ != null) hash ^= Error.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 (entry_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Entry); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (entry_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Entry); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetMempoolEntryResponseMessage other) { + if (other == null) { + return; + } + if (other.entry_ != null) { + if (entry_ == null) { + Entry = new global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry(); + } + Entry.MergeFrom(other.Entry); + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + if (entry_ == null) { + Entry = new global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry(); + } + input.ReadMessage(Entry); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetMempoolEntriesRequestMessage requests information about all the transactions + /// currently in the mempool. + /// + public sealed partial class GetMempoolEntriesRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMempoolEntriesRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[30]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesRequestMessage(GetMempoolEntriesRequestMessage other) : this() { + includeOrphanPool_ = other.includeOrphanPool_; + filterTransactionPool_ = other.filterTransactionPool_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesRequestMessage Clone() { + return new GetMempoolEntriesRequestMessage(this); + } + + /// Field number for the "includeOrphanPool" field. + public const int IncludeOrphanPoolFieldNumber = 1; + private bool includeOrphanPool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeOrphanPool { + get { return includeOrphanPool_; } + set { + includeOrphanPool_ = value; + } + } + + /// Field number for the "filterTransactionPool" field. + public const int FilterTransactionPoolFieldNumber = 2; + private bool filterTransactionPool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool FilterTransactionPool { + get { return filterTransactionPool_; } + set { + filterTransactionPool_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetMempoolEntriesRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetMempoolEntriesRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (IncludeOrphanPool != other.IncludeOrphanPool) return false; + if (FilterTransactionPool != other.FilterTransactionPool) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (IncludeOrphanPool != false) hash ^= IncludeOrphanPool.GetHashCode(); + if (FilterTransactionPool != false) hash ^= FilterTransactionPool.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 (IncludeOrphanPool != false) { + output.WriteRawTag(8); + output.WriteBool(IncludeOrphanPool); + } + if (FilterTransactionPool != false) { + output.WriteRawTag(16); + output.WriteBool(FilterTransactionPool); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (IncludeOrphanPool != false) { + size += 1 + 1; + } + if (FilterTransactionPool != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetMempoolEntriesRequestMessage other) { + if (other == null) { + return; + } + if (other.IncludeOrphanPool != false) { + IncludeOrphanPool = other.IncludeOrphanPool; + } + if (other.FilterTransactionPool != false) { + FilterTransactionPool = other.FilterTransactionPool; + } + _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 8: { + IncludeOrphanPool = input.ReadBool(); + break; + } + case 16: { + FilterTransactionPool = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class GetMempoolEntriesResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMempoolEntriesResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[31]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesResponseMessage(GetMempoolEntriesResponseMessage other) : this() { + entries_ = other.entries_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesResponseMessage Clone() { + return new GetMempoolEntriesResponseMessage(this); + } + + /// Field number for the "entries" field. + public const int EntriesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_entries_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry.Parser); + private readonly pbc::RepeatedField entries_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Entries { + get { return entries_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetMempoolEntriesResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetMempoolEntriesResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!entries_.Equals(other.entries_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= entries_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + entries_.WriteTo(output, _repeated_entries_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += entries_.CalculateSize(_repeated_entries_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetMempoolEntriesResponseMessage other) { + if (other == null) { + return; + } + entries_.Add(other.entries_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + entries_.AddEntriesFrom(input, _repeated_entries_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class MempoolEntry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MempoolEntry()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[32]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MempoolEntry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MempoolEntry(MempoolEntry other) : this() { + fee_ = other.fee_; + transaction_ = other.transaction_ != null ? other.transaction_.Clone() : null; + isOrphan_ = other.isOrphan_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MempoolEntry Clone() { + return new MempoolEntry(this); + } + + /// Field number for the "fee" field. + public const int FeeFieldNumber = 1; + private ulong fee_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Fee { + get { return fee_; } + set { + fee_ = value; + } + } + + /// Field number for the "transaction" field. + public const int TransactionFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction transaction_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction Transaction { + get { return transaction_; } + set { + transaction_ = value; + } + } + + /// Field number for the "isOrphan" field. + public const int IsOrphanFieldNumber = 4; + private bool isOrphan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsOrphan { + get { return isOrphan_; } + set { + isOrphan_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as MempoolEntry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(MempoolEntry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Fee != other.Fee) return false; + if (!object.Equals(Transaction, other.Transaction)) return false; + if (IsOrphan != other.IsOrphan) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Fee != 0UL) hash ^= Fee.GetHashCode(); + if (transaction_ != null) hash ^= Transaction.GetHashCode(); + if (IsOrphan != false) hash ^= IsOrphan.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 (Fee != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Fee); + } + if (transaction_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Transaction); + } + if (IsOrphan != false) { + output.WriteRawTag(32); + output.WriteBool(IsOrphan); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Fee != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Fee); + } + if (transaction_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Transaction); + } + if (IsOrphan != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(MempoolEntry other) { + if (other == null) { + return; + } + if (other.Fee != 0UL) { + Fee = other.Fee; + } + if (other.transaction_ != null) { + if (transaction_ == null) { + Transaction = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction(); + } + Transaction.MergeFrom(other.Transaction); + } + if (other.IsOrphan != false) { + IsOrphan = other.IsOrphan; + } + _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 8: { + Fee = input.ReadUInt64(); + break; + } + case 26: { + if (transaction_ == null) { + Transaction = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction(); + } + input.ReadMessage(Transaction); + break; + } + case 32: { + IsOrphan = input.ReadBool(); + break; + } + } + } + } + + } + + /// + /// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers + /// currently connected to this kaspad. + /// + public sealed partial class GetConnectedPeerInfoRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetConnectedPeerInfoRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[33]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoRequestMessage(GetConnectedPeerInfoRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoRequestMessage Clone() { + return new GetConnectedPeerInfoRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetConnectedPeerInfoRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetConnectedPeerInfoRequestMessage 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(GetConnectedPeerInfoRequestMessage 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 GetConnectedPeerInfoResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetConnectedPeerInfoResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[34]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoResponseMessage(GetConnectedPeerInfoResponseMessage other) : this() { + infos_ = other.infos_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoResponseMessage Clone() { + return new GetConnectedPeerInfoResponseMessage(this); + } + + /// Field number for the "infos" field. + public const int InfosFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_infos_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.GetConnectedPeerInfoMessage.Parser); + private readonly pbc::RepeatedField infos_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Infos { + get { return infos_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetConnectedPeerInfoResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetConnectedPeerInfoResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!infos_.Equals(other.infos_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= infos_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + infos_.WriteTo(output, _repeated_infos_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += infos_.CalculateSize(_repeated_infos_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetConnectedPeerInfoResponseMessage other) { + if (other == null) { + return; + } + infos_.Add(other.infos_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + infos_.AddEntriesFrom(input, _repeated_infos_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class GetConnectedPeerInfoMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetConnectedPeerInfoMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[35]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoMessage(GetConnectedPeerInfoMessage other) : this() { + id_ = other.id_; + address_ = other.address_; + lastPingDuration_ = other.lastPingDuration_; + isOutbound_ = other.isOutbound_; + timeOffset_ = other.timeOffset_; + userAgent_ = other.userAgent_; + advertisedProtocolVersion_ = other.advertisedProtocolVersion_; + timeConnected_ = other.timeConnected_; + isIbdPeer_ = other.isIbdPeer_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetConnectedPeerInfoMessage Clone() { + return new GetConnectedPeerInfoMessage(this); + } + + /// Field number for the "id" field. + public const int IdFieldNumber = 1; + private string id_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Id { + get { return id_; } + set { + id_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 2; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "lastPingDuration" field. + public const int LastPingDurationFieldNumber = 3; + private long lastPingDuration_; + /// + /// How long did the last ping/pong exchange take + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long LastPingDuration { + get { return lastPingDuration_; } + set { + lastPingDuration_ = value; + } + } + + /// Field number for the "isOutbound" field. + public const int IsOutboundFieldNumber = 6; + private bool isOutbound_; + /// + /// Whether this kaspad initiated the connection + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsOutbound { + get { return isOutbound_; } + set { + isOutbound_ = value; + } + } + + /// Field number for the "timeOffset" field. + public const int TimeOffsetFieldNumber = 7; + private long timeOffset_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long TimeOffset { + get { return timeOffset_; } + set { + timeOffset_ = value; + } + } + + /// Field number for the "userAgent" field. + public const int UserAgentFieldNumber = 8; + private string userAgent_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string UserAgent { + get { return userAgent_; } + set { + userAgent_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "advertisedProtocolVersion" field. + public const int AdvertisedProtocolVersionFieldNumber = 9; + private uint advertisedProtocolVersion_; + /// + /// The protocol version that this peer claims to support + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint AdvertisedProtocolVersion { + get { return advertisedProtocolVersion_; } + set { + advertisedProtocolVersion_ = value; + } + } + + /// Field number for the "timeConnected" field. + public const int TimeConnectedFieldNumber = 10; + private long timeConnected_; + /// + /// The timestamp of when this peer connected to this kaspad + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long TimeConnected { + get { return timeConnected_; } + set { + timeConnected_ = value; + } + } + + /// Field number for the "isIbdPeer" field. + public const int IsIbdPeerFieldNumber = 11; + private bool isIbdPeer_; + /// + /// Whether this peer is the IBD peer (if IBD is running) + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsIbdPeer { + get { return isIbdPeer_; } + set { + isIbdPeer_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetConnectedPeerInfoMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetConnectedPeerInfoMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Id != other.Id) return false; + if (Address != other.Address) return false; + if (LastPingDuration != other.LastPingDuration) return false; + if (IsOutbound != other.IsOutbound) return false; + if (TimeOffset != other.TimeOffset) return false; + if (UserAgent != other.UserAgent) return false; + if (AdvertisedProtocolVersion != other.AdvertisedProtocolVersion) return false; + if (TimeConnected != other.TimeConnected) return false; + if (IsIbdPeer != other.IsIbdPeer) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Id.Length != 0) hash ^= Id.GetHashCode(); + if (Address.Length != 0) hash ^= Address.GetHashCode(); + if (LastPingDuration != 0L) hash ^= LastPingDuration.GetHashCode(); + if (IsOutbound != false) hash ^= IsOutbound.GetHashCode(); + if (TimeOffset != 0L) hash ^= TimeOffset.GetHashCode(); + if (UserAgent.Length != 0) hash ^= UserAgent.GetHashCode(); + if (AdvertisedProtocolVersion != 0) hash ^= AdvertisedProtocolVersion.GetHashCode(); + if (TimeConnected != 0L) hash ^= TimeConnected.GetHashCode(); + if (IsIbdPeer != false) hash ^= IsIbdPeer.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 (Id.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Id); + } + if (Address.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Address); + } + if (LastPingDuration != 0L) { + output.WriteRawTag(24); + output.WriteInt64(LastPingDuration); + } + if (IsOutbound != false) { + output.WriteRawTag(48); + output.WriteBool(IsOutbound); + } + if (TimeOffset != 0L) { + output.WriteRawTag(56); + output.WriteInt64(TimeOffset); + } + if (UserAgent.Length != 0) { + output.WriteRawTag(66); + output.WriteString(UserAgent); + } + if (AdvertisedProtocolVersion != 0) { + output.WriteRawTag(72); + output.WriteUInt32(AdvertisedProtocolVersion); + } + if (TimeConnected != 0L) { + output.WriteRawTag(80); + output.WriteInt64(TimeConnected); + } + if (IsIbdPeer != false) { + output.WriteRawTag(88); + output.WriteBool(IsIbdPeer); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Id.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Id); + } + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (LastPingDuration != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(LastPingDuration); + } + if (IsOutbound != false) { + size += 1 + 1; + } + if (TimeOffset != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(TimeOffset); + } + if (UserAgent.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(UserAgent); + } + if (AdvertisedProtocolVersion != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(AdvertisedProtocolVersion); + } + if (TimeConnected != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(TimeConnected); + } + if (IsIbdPeer != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetConnectedPeerInfoMessage other) { + if (other == null) { + return; + } + if (other.Id.Length != 0) { + Id = other.Id; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + if (other.LastPingDuration != 0L) { + LastPingDuration = other.LastPingDuration; + } + if (other.IsOutbound != false) { + IsOutbound = other.IsOutbound; + } + if (other.TimeOffset != 0L) { + TimeOffset = other.TimeOffset; + } + if (other.UserAgent.Length != 0) { + UserAgent = other.UserAgent; + } + if (other.AdvertisedProtocolVersion != 0) { + AdvertisedProtocolVersion = other.AdvertisedProtocolVersion; + } + if (other.TimeConnected != 0L) { + TimeConnected = other.TimeConnected; + } + if (other.IsIbdPeer != false) { + IsIbdPeer = other.IsIbdPeer; + } + _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: { + Id = input.ReadString(); + break; + } + case 18: { + Address = input.ReadString(); + break; + } + case 24: { + LastPingDuration = input.ReadInt64(); + break; + } + case 48: { + IsOutbound = input.ReadBool(); + break; + } + case 56: { + TimeOffset = input.ReadInt64(); + break; + } + case 66: { + UserAgent = input.ReadString(); + break; + } + case 72: { + AdvertisedProtocolVersion = input.ReadUInt32(); + break; + } + case 80: { + TimeConnected = input.ReadInt64(); + break; + } + case 88: { + IsIbdPeer = input.ReadBool(); + break; + } + } + } + } + + } + + /// + /// AddPeerRequestMessage adds a peer to kaspad's outgoing connection list. + /// This will, in most cases, result in kaspad connecting to said peer. + /// + public sealed partial class AddPeerRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AddPeerRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[36]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddPeerRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddPeerRequestMessage(AddPeerRequestMessage other) : this() { + address_ = other.address_; + isPermanent_ = other.isPermanent_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddPeerRequestMessage Clone() { + return new AddPeerRequestMessage(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "isPermanent" field. + public const int IsPermanentFieldNumber = 2; + private bool isPermanent_; + /// + /// Whether to keep attempting to connect to this peer after disconnection + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsPermanent { + get { return isPermanent_; } + set { + isPermanent_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AddPeerRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AddPeerRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + if (IsPermanent != other.IsPermanent) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.GetHashCode(); + if (IsPermanent != false) hash ^= IsPermanent.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (IsPermanent != false) { + output.WriteRawTag(16); + output.WriteBool(IsPermanent); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (IsPermanent != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AddPeerRequestMessage other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + if (other.IsPermanent != false) { + IsPermanent = other.IsPermanent; + } + _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: { + Address = input.ReadString(); + break; + } + case 16: { + IsPermanent = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class AddPeerResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AddPeerResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[37]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddPeerResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddPeerResponseMessage(AddPeerResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AddPeerResponseMessage Clone() { + return new AddPeerResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AddPeerResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AddPeerResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AddPeerResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// SubmitTransactionRequestMessage submits a transaction to the mempool + /// + public sealed partial class SubmitTransactionRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SubmitTransactionRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[38]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitTransactionRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitTransactionRequestMessage(SubmitTransactionRequestMessage other) : this() { + transaction_ = other.transaction_ != null ? other.transaction_.Clone() : null; + allowOrphan_ = other.allowOrphan_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitTransactionRequestMessage Clone() { + return new SubmitTransactionRequestMessage(this); + } + + /// Field number for the "transaction" field. + public const int TransactionFieldNumber = 1; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction transaction_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction Transaction { + get { return transaction_; } + set { + transaction_ = value; + } + } + + /// Field number for the "allowOrphan" field. + public const int AllowOrphanFieldNumber = 2; + private bool allowOrphan_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool AllowOrphan { + get { return allowOrphan_; } + set { + allowOrphan_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SubmitTransactionRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SubmitTransactionRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Transaction, other.Transaction)) return false; + if (AllowOrphan != other.AllowOrphan) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (transaction_ != null) hash ^= Transaction.GetHashCode(); + if (AllowOrphan != false) hash ^= AllowOrphan.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 (transaction_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Transaction); + } + if (AllowOrphan != false) { + output.WriteRawTag(16); + output.WriteBool(AllowOrphan); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (transaction_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Transaction); + } + if (AllowOrphan != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SubmitTransactionRequestMessage other) { + if (other == null) { + return; + } + if (other.transaction_ != null) { + if (transaction_ == null) { + Transaction = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction(); + } + Transaction.MergeFrom(other.Transaction); + } + if (other.AllowOrphan != false) { + AllowOrphan = other.AllowOrphan; + } + _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: { + if (transaction_ == null) { + Transaction = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcTransaction(); + } + input.ReadMessage(Transaction); + break; + } + case 16: { + AllowOrphan = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class SubmitTransactionResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SubmitTransactionResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[39]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitTransactionResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitTransactionResponseMessage(SubmitTransactionResponseMessage other) : this() { + transactionId_ = other.transactionId_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public SubmitTransactionResponseMessage Clone() { + return new SubmitTransactionResponseMessage(this); + } + + /// Field number for the "transactionId" field. + public const int TransactionIdFieldNumber = 1; + private string transactionId_ = ""; + /// + /// The transaction ID of the submitted transaction + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string TransactionId { + get { return transactionId_; } + set { + transactionId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as SubmitTransactionResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(SubmitTransactionResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (TransactionId != other.TransactionId) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (TransactionId.Length != 0) hash ^= TransactionId.GetHashCode(); + if (error_ != null) hash ^= Error.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 (TransactionId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(TransactionId); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (TransactionId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(TransactionId); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(SubmitTransactionResponseMessage other) { + if (other == null) { + return; + } + if (other.TransactionId.Length != 0) { + TransactionId = other.TransactionId; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + TransactionId = input.ReadString(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// NotifyVirtualSelectedParentChainChangedRequestMessage registers this connection for virtualSelectedParentChainChanged notifications. + /// + /// See: VirtualSelectedParentChainChangedNotificationMessage + /// + public sealed partial class NotifyVirtualSelectedParentChainChangedRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyVirtualSelectedParentChainChangedRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[40]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentChainChangedRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentChainChangedRequestMessage(NotifyVirtualSelectedParentChainChangedRequestMessage other) : this() { + includeAcceptedTransactionIds_ = other.includeAcceptedTransactionIds_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentChainChangedRequestMessage Clone() { + return new NotifyVirtualSelectedParentChainChangedRequestMessage(this); + } + + /// Field number for the "includeAcceptedTransactionIds" field. + public const int IncludeAcceptedTransactionIdsFieldNumber = 1; + private bool includeAcceptedTransactionIds_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeAcceptedTransactionIds { + get { return includeAcceptedTransactionIds_; } + set { + includeAcceptedTransactionIds_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyVirtualSelectedParentChainChangedRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyVirtualSelectedParentChainChangedRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (IncludeAcceptedTransactionIds != other.IncludeAcceptedTransactionIds) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (IncludeAcceptedTransactionIds != false) hash ^= IncludeAcceptedTransactionIds.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 (IncludeAcceptedTransactionIds != false) { + output.WriteRawTag(8); + output.WriteBool(IncludeAcceptedTransactionIds); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (IncludeAcceptedTransactionIds != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyVirtualSelectedParentChainChangedRequestMessage other) { + if (other == null) { + return; + } + if (other.IncludeAcceptedTransactionIds != false) { + IncludeAcceptedTransactionIds = other.IncludeAcceptedTransactionIds; + } + _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 8: { + IncludeAcceptedTransactionIds = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class NotifyVirtualSelectedParentChainChangedResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyVirtualSelectedParentChainChangedResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[41]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentChainChangedResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentChainChangedResponseMessage(NotifyVirtualSelectedParentChainChangedResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentChainChangedResponseMessage Clone() { + return new NotifyVirtualSelectedParentChainChangedResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyVirtualSelectedParentChainChangedResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyVirtualSelectedParentChainChangedResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyVirtualSelectedParentChainChangedResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// VirtualSelectedParentChainChangedNotificationMessage is sent whenever the DAG's selected parent + /// chain had changed. + /// + /// See: NotifyVirtualSelectedParentChainChangedRequestMessage + /// + public sealed partial class VirtualSelectedParentChainChangedNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new VirtualSelectedParentChainChangedNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[42]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualSelectedParentChainChangedNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualSelectedParentChainChangedNotificationMessage(VirtualSelectedParentChainChangedNotificationMessage other) : this() { + removedChainBlockHashes_ = other.removedChainBlockHashes_.Clone(); + addedChainBlockHashes_ = other.addedChainBlockHashes_.Clone(); + acceptedTransactionIds_ = other.acceptedTransactionIds_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualSelectedParentChainChangedNotificationMessage Clone() { + return new VirtualSelectedParentChainChangedNotificationMessage(this); + } + + /// Field number for the "removedChainBlockHashes" field. + public const int RemovedChainBlockHashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_removedChainBlockHashes_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField removedChainBlockHashes_ = new pbc::RepeatedField(); + /// + /// The chain blocks that were removed, in high-to-low order + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField RemovedChainBlockHashes { + get { return removedChainBlockHashes_; } + } + + /// Field number for the "addedChainBlockHashes" field. + public const int AddedChainBlockHashesFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_addedChainBlockHashes_codec + = pb::FieldCodec.ForString(26); + private readonly pbc::RepeatedField addedChainBlockHashes_ = new pbc::RepeatedField(); + /// + /// The chain blocks that were added, in low-to-high order + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AddedChainBlockHashes { + get { return addedChainBlockHashes_; } + } + + /// Field number for the "acceptedTransactionIds" field. + public const int AcceptedTransactionIdsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_acceptedTransactionIds_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.AcceptedTransactionIds.Parser); + private readonly pbc::RepeatedField acceptedTransactionIds_ = new pbc::RepeatedField(); + /// + /// Will be filled only if `includeAcceptedTransactionIds = true` in the notify request. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AcceptedTransactionIds { + get { return acceptedTransactionIds_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as VirtualSelectedParentChainChangedNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(VirtualSelectedParentChainChangedNotificationMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!removedChainBlockHashes_.Equals(other.removedChainBlockHashes_)) return false; + if(!addedChainBlockHashes_.Equals(other.addedChainBlockHashes_)) return false; + if(!acceptedTransactionIds_.Equals(other.acceptedTransactionIds_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= removedChainBlockHashes_.GetHashCode(); + hash ^= addedChainBlockHashes_.GetHashCode(); + hash ^= acceptedTransactionIds_.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) { + removedChainBlockHashes_.WriteTo(output, _repeated_removedChainBlockHashes_codec); + acceptedTransactionIds_.WriteTo(output, _repeated_acceptedTransactionIds_codec); + addedChainBlockHashes_.WriteTo(output, _repeated_addedChainBlockHashes_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += removedChainBlockHashes_.CalculateSize(_repeated_removedChainBlockHashes_codec); + size += addedChainBlockHashes_.CalculateSize(_repeated_addedChainBlockHashes_codec); + size += acceptedTransactionIds_.CalculateSize(_repeated_acceptedTransactionIds_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(VirtualSelectedParentChainChangedNotificationMessage other) { + if (other == null) { + return; + } + removedChainBlockHashes_.Add(other.removedChainBlockHashes_); + addedChainBlockHashes_.Add(other.addedChainBlockHashes_); + acceptedTransactionIds_.Add(other.acceptedTransactionIds_); + _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: { + removedChainBlockHashes_.AddEntriesFrom(input, _repeated_removedChainBlockHashes_codec); + break; + } + case 18: { + acceptedTransactionIds_.AddEntriesFrom(input, _repeated_acceptedTransactionIds_codec); + break; + } + case 26: { + addedChainBlockHashes_.AddEntriesFrom(input, _repeated_addedChainBlockHashes_codec); + break; + } + } + } + } + + } + + /// + /// GetBlockRequestMessage requests information about a specific block + /// + public sealed partial class GetBlockRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[43]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockRequestMessage(GetBlockRequestMessage other) : this() { + hash_ = other.hash_; + includeTransactions_ = other.includeTransactions_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockRequestMessage Clone() { + return new GetBlockRequestMessage(this); + } + + /// Field number for the "hash" field. + public const int HashFieldNumber = 1; + private string hash_ = ""; + /// + /// The hash of the requested block + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Hash { + get { return hash_; } + set { + hash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "includeTransactions" field. + public const int IncludeTransactionsFieldNumber = 3; + private bool includeTransactions_; + /// + /// Whether to include transaction data in the response + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeTransactions { + get { return includeTransactions_; } + set { + includeTransactions_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Hash != other.Hash) return false; + if (IncludeTransactions != other.IncludeTransactions) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Hash.Length != 0) hash ^= Hash.GetHashCode(); + if (IncludeTransactions != false) hash ^= IncludeTransactions.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 (Hash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Hash); + } + if (IncludeTransactions != false) { + output.WriteRawTag(24); + output.WriteBool(IncludeTransactions); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Hash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Hash); + } + if (IncludeTransactions != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlockRequestMessage other) { + if (other == null) { + return; + } + if (other.Hash.Length != 0) { + Hash = other.Hash; + } + if (other.IncludeTransactions != false) { + IncludeTransactions = other.IncludeTransactions; + } + _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: { + Hash = input.ReadString(); + break; + } + case 24: { + IncludeTransactions = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class GetBlockResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[44]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockResponseMessage(GetBlockResponseMessage other) : this() { + block_ = other.block_ != null ? other.block_.Clone() : null; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockResponseMessage Clone() { + return new GetBlockResponseMessage(this); + } + + /// Field number for the "block" field. + public const int BlockFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock block_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock Block { + get { return block_; } + set { + block_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Block, other.Block)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (block_ != null) hash ^= Block.GetHashCode(); + if (error_ != null) hash ^= Error.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 (block_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Block); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (block_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Block); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlockResponseMessage other) { + if (other == null) { + return; + } + if (other.block_ != null) { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + Block.MergeFrom(other.Block); + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 26: { + if (block_ == null) { + Block = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock(); + } + input.ReadMessage(Block); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetSubnetworkRequestMessage requests information about a specific subnetwork + /// + /// Currently unimplemented + /// + public sealed partial class GetSubnetworkRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetSubnetworkRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[45]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSubnetworkRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSubnetworkRequestMessage(GetSubnetworkRequestMessage other) : this() { + subnetworkId_ = other.subnetworkId_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSubnetworkRequestMessage Clone() { + return new GetSubnetworkRequestMessage(this); + } + + /// Field number for the "subnetworkId" field. + public const int SubnetworkIdFieldNumber = 1; + private string subnetworkId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string SubnetworkId { + get { return subnetworkId_; } + set { + subnetworkId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetSubnetworkRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetSubnetworkRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (SubnetworkId != other.SubnetworkId) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (SubnetworkId.Length != 0) hash ^= SubnetworkId.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 (SubnetworkId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(SubnetworkId); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (SubnetworkId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(SubnetworkId); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetSubnetworkRequestMessage other) { + if (other == null) { + return; + } + if (other.SubnetworkId.Length != 0) { + SubnetworkId = other.SubnetworkId; + } + _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: { + SubnetworkId = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class GetSubnetworkResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetSubnetworkResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[46]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSubnetworkResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSubnetworkResponseMessage(GetSubnetworkResponseMessage other) : this() { + gasLimit_ = other.gasLimit_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetSubnetworkResponseMessage Clone() { + return new GetSubnetworkResponseMessage(this); + } + + /// Field number for the "gasLimit" field. + public const int GasLimitFieldNumber = 1; + private ulong gasLimit_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong GasLimit { + get { return gasLimit_; } + set { + gasLimit_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetSubnetworkResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetSubnetworkResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (GasLimit != other.GasLimit) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (GasLimit != 0UL) hash ^= GasLimit.GetHashCode(); + if (error_ != null) hash ^= Error.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 (GasLimit != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(GasLimit); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (GasLimit != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(GasLimit); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetSubnetworkResponseMessage other) { + if (other == null) { + return; + } + if (other.GasLimit != 0UL) { + GasLimit = other.GasLimit; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8: { + GasLimit = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetVirtualSelectedParentChainFromBlockRequestMessage requests the virtual selected + /// parent chain from some startHash to this kaspad's current virtual + /// + public sealed partial class GetVirtualSelectedParentChainFromBlockRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetVirtualSelectedParentChainFromBlockRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[47]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentChainFromBlockRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentChainFromBlockRequestMessage(GetVirtualSelectedParentChainFromBlockRequestMessage other) : this() { + startHash_ = other.startHash_; + includeAcceptedTransactionIds_ = other.includeAcceptedTransactionIds_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentChainFromBlockRequestMessage Clone() { + return new GetVirtualSelectedParentChainFromBlockRequestMessage(this); + } + + /// Field number for the "startHash" field. + public const int StartHashFieldNumber = 1; + private string startHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string StartHash { + get { return startHash_; } + set { + startHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "includeAcceptedTransactionIds" field. + public const int IncludeAcceptedTransactionIdsFieldNumber = 2; + private bool includeAcceptedTransactionIds_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeAcceptedTransactionIds { + get { return includeAcceptedTransactionIds_; } + set { + includeAcceptedTransactionIds_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetVirtualSelectedParentChainFromBlockRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetVirtualSelectedParentChainFromBlockRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (StartHash != other.StartHash) return false; + if (IncludeAcceptedTransactionIds != other.IncludeAcceptedTransactionIds) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (StartHash.Length != 0) hash ^= StartHash.GetHashCode(); + if (IncludeAcceptedTransactionIds != false) hash ^= IncludeAcceptedTransactionIds.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 (StartHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(StartHash); + } + if (IncludeAcceptedTransactionIds != false) { + output.WriteRawTag(16); + output.WriteBool(IncludeAcceptedTransactionIds); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (StartHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(StartHash); + } + if (IncludeAcceptedTransactionIds != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetVirtualSelectedParentChainFromBlockRequestMessage other) { + if (other == null) { + return; + } + if (other.StartHash.Length != 0) { + StartHash = other.StartHash; + } + if (other.IncludeAcceptedTransactionIds != false) { + IncludeAcceptedTransactionIds = other.IncludeAcceptedTransactionIds; + } + _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: { + StartHash = input.ReadString(); + break; + } + case 16: { + IncludeAcceptedTransactionIds = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class AcceptedTransactionIds : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AcceptedTransactionIds()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[48]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AcceptedTransactionIds() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AcceptedTransactionIds(AcceptedTransactionIds other) : this() { + acceptingBlockHash_ = other.acceptingBlockHash_; + acceptedTransactionIds_ = other.acceptedTransactionIds_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public AcceptedTransactionIds Clone() { + return new AcceptedTransactionIds(this); + } + + /// Field number for the "acceptingBlockHash" field. + public const int AcceptingBlockHashFieldNumber = 1; + private string acceptingBlockHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string AcceptingBlockHash { + get { return acceptingBlockHash_; } + set { + acceptingBlockHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "acceptedTransactionIds" field. + public const int AcceptedTransactionIds_FieldNumber = 2; + private static readonly pb::FieldCodec _repeated_acceptedTransactionIds_codec + = pb::FieldCodec.ForString(18); + private readonly pbc::RepeatedField acceptedTransactionIds_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AcceptedTransactionIds_ { + get { return acceptedTransactionIds_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as AcceptedTransactionIds); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(AcceptedTransactionIds other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (AcceptingBlockHash != other.AcceptingBlockHash) return false; + if(!acceptedTransactionIds_.Equals(other.acceptedTransactionIds_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (AcceptingBlockHash.Length != 0) hash ^= AcceptingBlockHash.GetHashCode(); + hash ^= acceptedTransactionIds_.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 (AcceptingBlockHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(AcceptingBlockHash); + } + acceptedTransactionIds_.WriteTo(output, _repeated_acceptedTransactionIds_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (AcceptingBlockHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(AcceptingBlockHash); + } + size += acceptedTransactionIds_.CalculateSize(_repeated_acceptedTransactionIds_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(AcceptedTransactionIds other) { + if (other == null) { + return; + } + if (other.AcceptingBlockHash.Length != 0) { + AcceptingBlockHash = other.AcceptingBlockHash; + } + acceptedTransactionIds_.Add(other.acceptedTransactionIds_); + _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: { + AcceptingBlockHash = input.ReadString(); + break; + } + case 18: { + acceptedTransactionIds_.AddEntriesFrom(input, _repeated_acceptedTransactionIds_codec); + break; + } + } + } + } + + } + + public sealed partial class GetVirtualSelectedParentChainFromBlockResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetVirtualSelectedParentChainFromBlockResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[49]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentChainFromBlockResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentChainFromBlockResponseMessage(GetVirtualSelectedParentChainFromBlockResponseMessage other) : this() { + removedChainBlockHashes_ = other.removedChainBlockHashes_.Clone(); + addedChainBlockHashes_ = other.addedChainBlockHashes_.Clone(); + acceptedTransactionIds_ = other.acceptedTransactionIds_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentChainFromBlockResponseMessage Clone() { + return new GetVirtualSelectedParentChainFromBlockResponseMessage(this); + } + + /// Field number for the "removedChainBlockHashes" field. + public const int RemovedChainBlockHashesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_removedChainBlockHashes_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField removedChainBlockHashes_ = new pbc::RepeatedField(); + /// + /// The chain blocks that were removed, in high-to-low order + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField RemovedChainBlockHashes { + get { return removedChainBlockHashes_; } + } + + /// Field number for the "addedChainBlockHashes" field. + public const int AddedChainBlockHashesFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_addedChainBlockHashes_codec + = pb::FieldCodec.ForString(26); + private readonly pbc::RepeatedField addedChainBlockHashes_ = new pbc::RepeatedField(); + /// + /// The chain blocks that were added, in low-to-high order + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AddedChainBlockHashes { + get { return addedChainBlockHashes_; } + } + + /// Field number for the "acceptedTransactionIds" field. + public const int AcceptedTransactionIdsFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_acceptedTransactionIds_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.AcceptedTransactionIds.Parser); + private readonly pbc::RepeatedField acceptedTransactionIds_ = new pbc::RepeatedField(); + /// + /// The transactions accepted by each block in addedChainBlockHashes. + /// Will be filled only if `includeAcceptedTransactionIds = true` in the request. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField AcceptedTransactionIds { + get { return acceptedTransactionIds_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetVirtualSelectedParentChainFromBlockResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetVirtualSelectedParentChainFromBlockResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!removedChainBlockHashes_.Equals(other.removedChainBlockHashes_)) return false; + if(!addedChainBlockHashes_.Equals(other.addedChainBlockHashes_)) return false; + if(!acceptedTransactionIds_.Equals(other.acceptedTransactionIds_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= removedChainBlockHashes_.GetHashCode(); + hash ^= addedChainBlockHashes_.GetHashCode(); + hash ^= acceptedTransactionIds_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + removedChainBlockHashes_.WriteTo(output, _repeated_removedChainBlockHashes_codec); + acceptedTransactionIds_.WriteTo(output, _repeated_acceptedTransactionIds_codec); + addedChainBlockHashes_.WriteTo(output, _repeated_addedChainBlockHashes_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += removedChainBlockHashes_.CalculateSize(_repeated_removedChainBlockHashes_codec); + size += addedChainBlockHashes_.CalculateSize(_repeated_addedChainBlockHashes_codec); + size += acceptedTransactionIds_.CalculateSize(_repeated_acceptedTransactionIds_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetVirtualSelectedParentChainFromBlockResponseMessage other) { + if (other == null) { + return; + } + removedChainBlockHashes_.Add(other.removedChainBlockHashes_); + addedChainBlockHashes_.Add(other.addedChainBlockHashes_); + acceptedTransactionIds_.Add(other.acceptedTransactionIds_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + removedChainBlockHashes_.AddEntriesFrom(input, _repeated_removedChainBlockHashes_codec); + break; + } + case 18: { + acceptedTransactionIds_.AddEntriesFrom(input, _repeated_acceptedTransactionIds_codec); + break; + } + case 26: { + addedChainBlockHashes_.AddEntriesFrom(input, _repeated_addedChainBlockHashes_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetBlocksRequestMessage requests blocks between a certain block lowHash up to this + /// kaspad's current virtual. + /// + public sealed partial class GetBlocksRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlocksRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[50]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlocksRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlocksRequestMessage(GetBlocksRequestMessage other) : this() { + lowHash_ = other.lowHash_; + includeBlocks_ = other.includeBlocks_; + includeTransactions_ = other.includeTransactions_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlocksRequestMessage Clone() { + return new GetBlocksRequestMessage(this); + } + + /// Field number for the "lowHash" field. + public const int LowHashFieldNumber = 1; + private string lowHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string LowHash { + get { return lowHash_; } + set { + lowHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "includeBlocks" field. + public const int IncludeBlocksFieldNumber = 2; + private bool includeBlocks_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeBlocks { + get { return includeBlocks_; } + set { + includeBlocks_ = value; + } + } + + /// Field number for the "includeTransactions" field. + public const int IncludeTransactionsFieldNumber = 3; + private bool includeTransactions_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeTransactions { + get { return includeTransactions_; } + set { + includeTransactions_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlocksRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlocksRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (LowHash != other.LowHash) return false; + if (IncludeBlocks != other.IncludeBlocks) return false; + if (IncludeTransactions != other.IncludeTransactions) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (LowHash.Length != 0) hash ^= LowHash.GetHashCode(); + if (IncludeBlocks != false) hash ^= IncludeBlocks.GetHashCode(); + if (IncludeTransactions != false) hash ^= IncludeTransactions.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 (LowHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(LowHash); + } + if (IncludeBlocks != false) { + output.WriteRawTag(16); + output.WriteBool(IncludeBlocks); + } + if (IncludeTransactions != false) { + output.WriteRawTag(24); + output.WriteBool(IncludeTransactions); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (LowHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(LowHash); + } + if (IncludeBlocks != false) { + size += 1 + 1; + } + if (IncludeTransactions != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlocksRequestMessage other) { + if (other == null) { + return; + } + if (other.LowHash.Length != 0) { + LowHash = other.LowHash; + } + if (other.IncludeBlocks != false) { + IncludeBlocks = other.IncludeBlocks; + } + if (other.IncludeTransactions != false) { + IncludeTransactions = other.IncludeTransactions; + } + _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: { + LowHash = input.ReadString(); + break; + } + case 16: { + IncludeBlocks = input.ReadBool(); + break; + } + case 24: { + IncludeTransactions = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class GetBlocksResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlocksResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[51]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlocksResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlocksResponseMessage(GetBlocksResponseMessage other) : this() { + blockHashes_ = other.blockHashes_.Clone(); + blocks_ = other.blocks_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlocksResponseMessage Clone() { + return new GetBlocksResponseMessage(this); + } + + /// Field number for the "blockHashes" field. + public const int BlockHashesFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_blockHashes_codec + = pb::FieldCodec.ForString(34); + private readonly pbc::RepeatedField blockHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField BlockHashes { + get { return blockHashes_; } + } + + /// Field number for the "blocks" field. + public const int BlocksFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_blocks_codec + = pb::FieldCodec.ForMessage(26, global::Miningcore.Blockchain.Kaspa.Kaspad.RpcBlock.Parser); + private readonly pbc::RepeatedField blocks_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Blocks { + get { return blocks_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlocksResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlocksResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!blockHashes_.Equals(other.blockHashes_)) return false; + if(!blocks_.Equals(other.blocks_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= blockHashes_.GetHashCode(); + hash ^= blocks_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + blocks_.WriteTo(output, _repeated_blocks_codec); + blockHashes_.WriteTo(output, _repeated_blockHashes_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += blockHashes_.CalculateSize(_repeated_blockHashes_codec); + size += blocks_.CalculateSize(_repeated_blocks_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlocksResponseMessage other) { + if (other == null) { + return; + } + blockHashes_.Add(other.blockHashes_); + blocks_.Add(other.blocks_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 26: { + blocks_.AddEntriesFrom(input, _repeated_blocks_codec); + break; + } + case 34: { + blockHashes_.AddEntriesFrom(input, _repeated_blockHashes_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetBlockCountRequestMessage requests the current number of blocks in this kaspad. + /// Note that this number may decrease as pruning occurs. + /// + public sealed partial class GetBlockCountRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockCountRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[52]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockCountRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockCountRequestMessage(GetBlockCountRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockCountRequestMessage Clone() { + return new GetBlockCountRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockCountRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockCountRequestMessage 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(GetBlockCountRequestMessage 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 GetBlockCountResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockCountResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[53]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockCountResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockCountResponseMessage(GetBlockCountResponseMessage other) : this() { + blockCount_ = other.blockCount_; + headerCount_ = other.headerCount_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockCountResponseMessage Clone() { + return new GetBlockCountResponseMessage(this); + } + + /// Field number for the "blockCount" field. + public const int BlockCountFieldNumber = 1; + private ulong blockCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlockCount { + get { return blockCount_; } + set { + blockCount_ = value; + } + } + + /// Field number for the "headerCount" field. + public const int HeaderCountFieldNumber = 2; + private ulong headerCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong HeaderCount { + get { return headerCount_; } + set { + headerCount_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockCountResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockCountResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (BlockCount != other.BlockCount) return false; + if (HeaderCount != other.HeaderCount) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (BlockCount != 0UL) hash ^= BlockCount.GetHashCode(); + if (HeaderCount != 0UL) hash ^= HeaderCount.GetHashCode(); + if (error_ != null) hash ^= Error.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 (BlockCount != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(BlockCount); + } + if (HeaderCount != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(HeaderCount); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (BlockCount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlockCount); + } + if (HeaderCount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(HeaderCount); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlockCountResponseMessage other) { + if (other == null) { + return; + } + if (other.BlockCount != 0UL) { + BlockCount = other.BlockCount; + } + if (other.HeaderCount != 0UL) { + HeaderCount = other.HeaderCount; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8: { + BlockCount = input.ReadUInt64(); + break; + } + case 16: { + HeaderCount = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetBlockDagInfoRequestMessage requests general information about the current state + /// of this kaspad's DAG. + /// + public sealed partial class GetBlockDagInfoRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockDagInfoRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[54]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockDagInfoRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockDagInfoRequestMessage(GetBlockDagInfoRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockDagInfoRequestMessage Clone() { + return new GetBlockDagInfoRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockDagInfoRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockDagInfoRequestMessage 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(GetBlockDagInfoRequestMessage 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 GetBlockDagInfoResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBlockDagInfoResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[55]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockDagInfoResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockDagInfoResponseMessage(GetBlockDagInfoResponseMessage other) : this() { + networkName_ = other.networkName_; + blockCount_ = other.blockCount_; + headerCount_ = other.headerCount_; + tipHashes_ = other.tipHashes_.Clone(); + difficulty_ = other.difficulty_; + pastMedianTime_ = other.pastMedianTime_; + virtualParentHashes_ = other.virtualParentHashes_.Clone(); + pruningPointHash_ = other.pruningPointHash_; + virtualDaaScore_ = other.virtualDaaScore_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBlockDagInfoResponseMessage Clone() { + return new GetBlockDagInfoResponseMessage(this); + } + + /// Field number for the "networkName" field. + public const int NetworkNameFieldNumber = 1; + private string networkName_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string NetworkName { + get { return networkName_; } + set { + networkName_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "blockCount" field. + public const int BlockCountFieldNumber = 2; + private ulong blockCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlockCount { + get { return blockCount_; } + set { + blockCount_ = value; + } + } + + /// Field number for the "headerCount" field. + public const int HeaderCountFieldNumber = 3; + private ulong headerCount_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong HeaderCount { + get { return headerCount_; } + set { + headerCount_ = value; + } + } + + /// Field number for the "tipHashes" field. + public const int TipHashesFieldNumber = 4; + private static readonly pb::FieldCodec _repeated_tipHashes_codec + = pb::FieldCodec.ForString(34); + private readonly pbc::RepeatedField tipHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField TipHashes { + get { return tipHashes_; } + } + + /// Field number for the "difficulty" field. + public const int DifficultyFieldNumber = 5; + private double difficulty_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public double Difficulty { + get { return difficulty_; } + set { + difficulty_ = value; + } + } + + /// Field number for the "pastMedianTime" field. + public const int PastMedianTimeFieldNumber = 6; + private long pastMedianTime_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public long PastMedianTime { + get { return pastMedianTime_; } + set { + pastMedianTime_ = value; + } + } + + /// Field number for the "virtualParentHashes" field. + public const int VirtualParentHashesFieldNumber = 7; + private static readonly pb::FieldCodec _repeated_virtualParentHashes_codec + = pb::FieldCodec.ForString(58); + private readonly pbc::RepeatedField virtualParentHashes_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField VirtualParentHashes { + get { return virtualParentHashes_; } + } + + /// Field number for the "pruningPointHash" field. + public const int PruningPointHashFieldNumber = 8; + private string pruningPointHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string PruningPointHash { + get { return pruningPointHash_; } + set { + pruningPointHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "virtualDaaScore" field. + public const int VirtualDaaScoreFieldNumber = 9; + private ulong virtualDaaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong VirtualDaaScore { + get { return virtualDaaScore_; } + set { + virtualDaaScore_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBlockDagInfoResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBlockDagInfoResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (NetworkName != other.NetworkName) return false; + if (BlockCount != other.BlockCount) return false; + if (HeaderCount != other.HeaderCount) return false; + if(!tipHashes_.Equals(other.tipHashes_)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(Difficulty, other.Difficulty)) return false; + if (PastMedianTime != other.PastMedianTime) return false; + if(!virtualParentHashes_.Equals(other.virtualParentHashes_)) return false; + if (PruningPointHash != other.PruningPointHash) return false; + if (VirtualDaaScore != other.VirtualDaaScore) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (NetworkName.Length != 0) hash ^= NetworkName.GetHashCode(); + if (BlockCount != 0UL) hash ^= BlockCount.GetHashCode(); + if (HeaderCount != 0UL) hash ^= HeaderCount.GetHashCode(); + hash ^= tipHashes_.GetHashCode(); + if (Difficulty != 0D) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(Difficulty); + if (PastMedianTime != 0L) hash ^= PastMedianTime.GetHashCode(); + hash ^= virtualParentHashes_.GetHashCode(); + if (PruningPointHash.Length != 0) hash ^= PruningPointHash.GetHashCode(); + if (VirtualDaaScore != 0UL) hash ^= VirtualDaaScore.GetHashCode(); + if (error_ != null) hash ^= Error.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 (NetworkName.Length != 0) { + output.WriteRawTag(10); + output.WriteString(NetworkName); + } + if (BlockCount != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(BlockCount); + } + if (HeaderCount != 0UL) { + output.WriteRawTag(24); + output.WriteUInt64(HeaderCount); + } + tipHashes_.WriteTo(output, _repeated_tipHashes_codec); + if (Difficulty != 0D) { + output.WriteRawTag(41); + output.WriteDouble(Difficulty); + } + if (PastMedianTime != 0L) { + output.WriteRawTag(48); + output.WriteInt64(PastMedianTime); + } + virtualParentHashes_.WriteTo(output, _repeated_virtualParentHashes_codec); + if (PruningPointHash.Length != 0) { + output.WriteRawTag(66); + output.WriteString(PruningPointHash); + } + if (VirtualDaaScore != 0UL) { + output.WriteRawTag(72); + output.WriteUInt64(VirtualDaaScore); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (NetworkName.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(NetworkName); + } + if (BlockCount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlockCount); + } + if (HeaderCount != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(HeaderCount); + } + size += tipHashes_.CalculateSize(_repeated_tipHashes_codec); + if (Difficulty != 0D) { + size += 1 + 8; + } + if (PastMedianTime != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(PastMedianTime); + } + size += virtualParentHashes_.CalculateSize(_repeated_virtualParentHashes_codec); + if (PruningPointHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(PruningPointHash); + } + if (VirtualDaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(VirtualDaaScore); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBlockDagInfoResponseMessage other) { + if (other == null) { + return; + } + if (other.NetworkName.Length != 0) { + NetworkName = other.NetworkName; + } + if (other.BlockCount != 0UL) { + BlockCount = other.BlockCount; + } + if (other.HeaderCount != 0UL) { + HeaderCount = other.HeaderCount; + } + tipHashes_.Add(other.tipHashes_); + if (other.Difficulty != 0D) { + Difficulty = other.Difficulty; + } + if (other.PastMedianTime != 0L) { + PastMedianTime = other.PastMedianTime; + } + virtualParentHashes_.Add(other.virtualParentHashes_); + if (other.PruningPointHash.Length != 0) { + PruningPointHash = other.PruningPointHash; + } + if (other.VirtualDaaScore != 0UL) { + VirtualDaaScore = other.VirtualDaaScore; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + NetworkName = input.ReadString(); + break; + } + case 16: { + BlockCount = input.ReadUInt64(); + break; + } + case 24: { + HeaderCount = input.ReadUInt64(); + break; + } + case 34: { + tipHashes_.AddEntriesFrom(input, _repeated_tipHashes_codec); + break; + } + case 41: { + Difficulty = input.ReadDouble(); + break; + } + case 48: { + PastMedianTime = input.ReadInt64(); + break; + } + case 58: { + virtualParentHashes_.AddEntriesFrom(input, _repeated_virtualParentHashes_codec); + break; + } + case 66: { + PruningPointHash = input.ReadString(); + break; + } + case 72: { + VirtualDaaScore = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class ResolveFinalityConflictRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResolveFinalityConflictRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[56]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResolveFinalityConflictRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResolveFinalityConflictRequestMessage(ResolveFinalityConflictRequestMessage other) : this() { + finalityBlockHash_ = other.finalityBlockHash_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResolveFinalityConflictRequestMessage Clone() { + return new ResolveFinalityConflictRequestMessage(this); + } + + /// Field number for the "finalityBlockHash" field. + public const int FinalityBlockHashFieldNumber = 1; + private string finalityBlockHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FinalityBlockHash { + get { return finalityBlockHash_; } + set { + finalityBlockHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ResolveFinalityConflictRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ResolveFinalityConflictRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FinalityBlockHash != other.FinalityBlockHash) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FinalityBlockHash.Length != 0) hash ^= FinalityBlockHash.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 (FinalityBlockHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FinalityBlockHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FinalityBlockHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FinalityBlockHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ResolveFinalityConflictRequestMessage other) { + if (other == null) { + return; + } + if (other.FinalityBlockHash.Length != 0) { + FinalityBlockHash = other.FinalityBlockHash; + } + _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: { + FinalityBlockHash = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class ResolveFinalityConflictResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResolveFinalityConflictResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[57]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResolveFinalityConflictResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResolveFinalityConflictResponseMessage(ResolveFinalityConflictResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ResolveFinalityConflictResponseMessage Clone() { + return new ResolveFinalityConflictResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ResolveFinalityConflictResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ResolveFinalityConflictResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ResolveFinalityConflictResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class NotifyFinalityConflictsRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyFinalityConflictsRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[58]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyFinalityConflictsRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyFinalityConflictsRequestMessage(NotifyFinalityConflictsRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyFinalityConflictsRequestMessage Clone() { + return new NotifyFinalityConflictsRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyFinalityConflictsRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyFinalityConflictsRequestMessage 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(NotifyFinalityConflictsRequestMessage 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 NotifyFinalityConflictsResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyFinalityConflictsResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[59]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyFinalityConflictsResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyFinalityConflictsResponseMessage(NotifyFinalityConflictsResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyFinalityConflictsResponseMessage Clone() { + return new NotifyFinalityConflictsResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyFinalityConflictsResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyFinalityConflictsResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyFinalityConflictsResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class FinalityConflictNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FinalityConflictNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[60]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FinalityConflictNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FinalityConflictNotificationMessage(FinalityConflictNotificationMessage other) : this() { + violatingBlockHash_ = other.violatingBlockHash_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FinalityConflictNotificationMessage Clone() { + return new FinalityConflictNotificationMessage(this); + } + + /// Field number for the "violatingBlockHash" field. + public const int ViolatingBlockHashFieldNumber = 1; + private string violatingBlockHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ViolatingBlockHash { + get { return violatingBlockHash_; } + set { + violatingBlockHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as FinalityConflictNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(FinalityConflictNotificationMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ViolatingBlockHash != other.ViolatingBlockHash) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (ViolatingBlockHash.Length != 0) hash ^= ViolatingBlockHash.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 (ViolatingBlockHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(ViolatingBlockHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (ViolatingBlockHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ViolatingBlockHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(FinalityConflictNotificationMessage other) { + if (other == null) { + return; + } + if (other.ViolatingBlockHash.Length != 0) { + ViolatingBlockHash = other.ViolatingBlockHash; + } + _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: { + ViolatingBlockHash = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class FinalityConflictResolvedNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FinalityConflictResolvedNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[61]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FinalityConflictResolvedNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FinalityConflictResolvedNotificationMessage(FinalityConflictResolvedNotificationMessage other) : this() { + finalityBlockHash_ = other.finalityBlockHash_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public FinalityConflictResolvedNotificationMessage Clone() { + return new FinalityConflictResolvedNotificationMessage(this); + } + + /// Field number for the "finalityBlockHash" field. + public const int FinalityBlockHashFieldNumber = 1; + private string finalityBlockHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string FinalityBlockHash { + get { return finalityBlockHash_; } + set { + finalityBlockHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as FinalityConflictResolvedNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(FinalityConflictResolvedNotificationMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (FinalityBlockHash != other.FinalityBlockHash) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (FinalityBlockHash.Length != 0) hash ^= FinalityBlockHash.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 (FinalityBlockHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(FinalityBlockHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (FinalityBlockHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(FinalityBlockHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(FinalityConflictResolvedNotificationMessage other) { + if (other == null) { + return; + } + if (other.FinalityBlockHash.Length != 0) { + FinalityBlockHash = other.FinalityBlockHash; + } + _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: { + FinalityBlockHash = input.ReadString(); + break; + } + } + } + } + + } + + /// + /// ShutDownRequestMessage shuts down this kaspad. + /// + public sealed partial class ShutDownRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShutDownRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[62]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutDownRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutDownRequestMessage(ShutDownRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutDownRequestMessage Clone() { + return new ShutDownRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ShutDownRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ShutDownRequestMessage 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(ShutDownRequestMessage 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 ShutDownResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ShutDownResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[63]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutDownResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutDownResponseMessage(ShutDownResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ShutDownResponseMessage Clone() { + return new ShutDownResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as ShutDownResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(ShutDownResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(ShutDownResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetHeadersRequestMessage requests headers between the given startHash and the + /// current virtual, up to the given limit. + /// + public sealed partial class GetHeadersRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetHeadersRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[64]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHeadersRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHeadersRequestMessage(GetHeadersRequestMessage other) : this() { + startHash_ = other.startHash_; + limit_ = other.limit_; + isAscending_ = other.isAscending_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHeadersRequestMessage Clone() { + return new GetHeadersRequestMessage(this); + } + + /// Field number for the "startHash" field. + public const int StartHashFieldNumber = 1; + private string startHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string StartHash { + get { return startHash_; } + set { + startHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "limit" field. + public const int LimitFieldNumber = 2; + private ulong limit_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Limit { + get { return limit_; } + set { + limit_ = value; + } + } + + /// Field number for the "isAscending" field. + public const int IsAscendingFieldNumber = 3; + private bool isAscending_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsAscending { + get { return isAscending_; } + set { + isAscending_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetHeadersRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetHeadersRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (StartHash != other.StartHash) return false; + if (Limit != other.Limit) return false; + if (IsAscending != other.IsAscending) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (StartHash.Length != 0) hash ^= StartHash.GetHashCode(); + if (Limit != 0UL) hash ^= Limit.GetHashCode(); + if (IsAscending != false) hash ^= IsAscending.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 (StartHash.Length != 0) { + output.WriteRawTag(10); + output.WriteString(StartHash); + } + if (Limit != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(Limit); + } + if (IsAscending != false) { + output.WriteRawTag(24); + output.WriteBool(IsAscending); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (StartHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(StartHash); + } + if (Limit != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Limit); + } + if (IsAscending != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetHeadersRequestMessage other) { + if (other == null) { + return; + } + if (other.StartHash.Length != 0) { + StartHash = other.StartHash; + } + if (other.Limit != 0UL) { + Limit = other.Limit; + } + if (other.IsAscending != false) { + IsAscending = other.IsAscending; + } + _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: { + StartHash = input.ReadString(); + break; + } + case 16: { + Limit = input.ReadUInt64(); + break; + } + case 24: { + IsAscending = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class GetHeadersResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetHeadersResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[65]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHeadersResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHeadersResponseMessage(GetHeadersResponseMessage other) : this() { + headers_ = other.headers_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetHeadersResponseMessage Clone() { + return new GetHeadersResponseMessage(this); + } + + /// Field number for the "headers" field. + public const int HeadersFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_headers_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField headers_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Headers { + get { return headers_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetHeadersResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetHeadersResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!headers_.Equals(other.headers_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= headers_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + headers_.WriteTo(output, _repeated_headers_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += headers_.CalculateSize(_repeated_headers_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetHeadersResponseMessage other) { + if (other == null) { + return; + } + headers_.Add(other.headers_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + headers_.AddEntriesFrom(input, _repeated_headers_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications + /// for the given addresses. + /// + /// This call is only available when this kaspad was started with `--utxoindex` + /// + /// See: UtxosChangedNotificationMessage + /// + public sealed partial class NotifyUtxosChangedRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyUtxosChangedRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[66]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyUtxosChangedRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyUtxosChangedRequestMessage(NotifyUtxosChangedRequestMessage other) : this() { + addresses_ = other.addresses_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyUtxosChangedRequestMessage Clone() { + return new NotifyUtxosChangedRequestMessage(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + /// + /// Leave empty to get all updates + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyUtxosChangedRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyUtxosChangedRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.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) { + addresses_.WriteTo(output, _repeated_addresses_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyUtxosChangedRequestMessage other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + _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: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + } + } + } + + } + + public sealed partial class NotifyUtxosChangedResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyUtxosChangedResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[67]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyUtxosChangedResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyUtxosChangedResponseMessage(NotifyUtxosChangedResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyUtxosChangedResponseMessage Clone() { + return new NotifyUtxosChangedResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyUtxosChangedResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyUtxosChangedResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyUtxosChangedResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// UtxosChangedNotificationMessage is sent whenever the UTXO index had been updated. + /// + /// See: NotifyUtxosChangedRequestMessage + /// + public sealed partial class UtxosChangedNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UtxosChangedNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[68]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosChangedNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosChangedNotificationMessage(UtxosChangedNotificationMessage other) : this() { + added_ = other.added_.Clone(); + removed_ = other.removed_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosChangedNotificationMessage Clone() { + return new UtxosChangedNotificationMessage(this); + } + + /// Field number for the "added" field. + public const int AddedFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_added_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosByAddressesEntry.Parser); + private readonly pbc::RepeatedField added_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Added { + get { return added_; } + } + + /// Field number for the "removed" field. + public const int RemovedFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_removed_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosByAddressesEntry.Parser); + private readonly pbc::RepeatedField removed_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Removed { + get { return removed_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UtxosChangedNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UtxosChangedNotificationMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!added_.Equals(other.added_)) return false; + if(!removed_.Equals(other.removed_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= added_.GetHashCode(); + hash ^= removed_.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) { + added_.WriteTo(output, _repeated_added_codec); + removed_.WriteTo(output, _repeated_removed_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += added_.CalculateSize(_repeated_added_codec); + size += removed_.CalculateSize(_repeated_removed_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UtxosChangedNotificationMessage other) { + if (other == null) { + return; + } + added_.Add(other.added_); + removed_.Add(other.removed_); + _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: { + added_.AddEntriesFrom(input, _repeated_added_codec); + break; + } + case 18: { + removed_.AddEntriesFrom(input, _repeated_removed_codec); + break; + } + } + } + } + + } + + public sealed partial class UtxosByAddressesEntry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UtxosByAddressesEntry()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[69]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosByAddressesEntry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosByAddressesEntry(UtxosByAddressesEntry other) : this() { + address_ = other.address_; + outpoint_ = other.outpoint_ != null ? other.outpoint_.Clone() : null; + utxoEntry_ = other.utxoEntry_ != null ? other.utxoEntry_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UtxosByAddressesEntry Clone() { + return new UtxosByAddressesEntry(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "outpoint" field. + public const int OutpointFieldNumber = 2; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint outpoint_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint Outpoint { + get { return outpoint_; } + set { + outpoint_ = value; + } + } + + /// Field number for the "utxoEntry" field. + public const int UtxoEntryFieldNumber = 3; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RpcUtxoEntry utxoEntry_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RpcUtxoEntry UtxoEntry { + get { return utxoEntry_; } + set { + utxoEntry_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UtxosByAddressesEntry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UtxosByAddressesEntry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + if (!object.Equals(Outpoint, other.Outpoint)) return false; + if (!object.Equals(UtxoEntry, other.UtxoEntry)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.GetHashCode(); + if (outpoint_ != null) hash ^= Outpoint.GetHashCode(); + if (utxoEntry_ != null) hash ^= UtxoEntry.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (outpoint_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Outpoint); + } + if (utxoEntry_ != null) { + output.WriteRawTag(26); + output.WriteMessage(UtxoEntry); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (outpoint_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Outpoint); + } + if (utxoEntry_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(UtxoEntry); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UtxosByAddressesEntry other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + if (other.outpoint_ != null) { + if (outpoint_ == null) { + Outpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint(); + } + Outpoint.MergeFrom(other.Outpoint); + } + if (other.utxoEntry_ != null) { + if (utxoEntry_ == null) { + UtxoEntry = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcUtxoEntry(); + } + UtxoEntry.MergeFrom(other.UtxoEntry); + } + _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: { + Address = input.ReadString(); + break; + } + case 18: { + if (outpoint_ == null) { + Outpoint = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcOutpoint(); + } + input.ReadMessage(Outpoint); + break; + } + case 26: { + if (utxoEntry_ == null) { + UtxoEntry = new global::Miningcore.Blockchain.Kaspa.Kaspad.RpcUtxoEntry(); + } + input.ReadMessage(UtxoEntry); + break; + } + } + } + } + + } + + /// + /// StopNotifyingUtxosChangedRequestMessage unregisters this connection for utxoChanged notifications + /// for the given addresses. + /// + /// This call is only available when this kaspad was started with `--utxoindex` + /// + /// See: UtxosChangedNotificationMessage + /// + public sealed partial class StopNotifyingUtxosChangedRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StopNotifyingUtxosChangedRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[70]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingUtxosChangedRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingUtxosChangedRequestMessage(StopNotifyingUtxosChangedRequestMessage other) : this() { + addresses_ = other.addresses_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingUtxosChangedRequestMessage Clone() { + return new StopNotifyingUtxosChangedRequestMessage(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StopNotifyingUtxosChangedRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StopNotifyingUtxosChangedRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.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) { + addresses_.WriteTo(output, _repeated_addresses_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(StopNotifyingUtxosChangedRequestMessage other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + _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: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + } + } + } + + } + + public sealed partial class StopNotifyingUtxosChangedResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StopNotifyingUtxosChangedResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[71]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingUtxosChangedResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingUtxosChangedResponseMessage(StopNotifyingUtxosChangedResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingUtxosChangedResponseMessage Clone() { + return new StopNotifyingUtxosChangedResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StopNotifyingUtxosChangedResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StopNotifyingUtxosChangedResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(StopNotifyingUtxosChangedResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses + /// + /// This call is only available when this kaspad was started with `--utxoindex` + /// + public sealed partial class GetUtxosByAddressesRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetUtxosByAddressesRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[72]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetUtxosByAddressesRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetUtxosByAddressesRequestMessage(GetUtxosByAddressesRequestMessage other) : this() { + addresses_ = other.addresses_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetUtxosByAddressesRequestMessage Clone() { + return new GetUtxosByAddressesRequestMessage(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetUtxosByAddressesRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetUtxosByAddressesRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.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) { + addresses_.WriteTo(output, _repeated_addresses_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetUtxosByAddressesRequestMessage other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + _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: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + } + } + } + + } + + public sealed partial class GetUtxosByAddressesResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetUtxosByAddressesResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[73]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetUtxosByAddressesResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetUtxosByAddressesResponseMessage(GetUtxosByAddressesResponseMessage other) : this() { + entries_ = other.entries_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetUtxosByAddressesResponseMessage Clone() { + return new GetUtxosByAddressesResponseMessage(this); + } + + /// Field number for the "entries" field. + public const int EntriesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_entries_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.UtxosByAddressesEntry.Parser); + private readonly pbc::RepeatedField entries_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Entries { + get { return entries_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetUtxosByAddressesResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetUtxosByAddressesResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!entries_.Equals(other.entries_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= entries_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + entries_.WriteTo(output, _repeated_entries_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += entries_.CalculateSize(_repeated_entries_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetUtxosByAddressesResponseMessage other) { + if (other == null) { + return; + } + entries_.Add(other.entries_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + entries_.AddEntriesFrom(input, _repeated_entries_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetBalanceByAddressRequest returns the total balance in unspent transactions towards a given address + /// + /// This call is only available when this kaspad was started with `--utxoindex` + /// + public sealed partial class GetBalanceByAddressRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBalanceByAddressRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[74]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceByAddressRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceByAddressRequestMessage(GetBalanceByAddressRequestMessage other) : this() { + address_ = other.address_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceByAddressRequestMessage Clone() { + return new GetBalanceByAddressRequestMessage(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBalanceByAddressRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBalanceByAddressRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBalanceByAddressRequestMessage other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + _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: { + Address = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class GetBalanceByAddressResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBalanceByAddressResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[75]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceByAddressResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceByAddressResponseMessage(GetBalanceByAddressResponseMessage other) : this() { + balance_ = other.balance_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalanceByAddressResponseMessage Clone() { + return new GetBalanceByAddressResponseMessage(this); + } + + /// Field number for the "balance" field. + public const int BalanceFieldNumber = 1; + private ulong balance_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Balance { + get { return balance_; } + set { + balance_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBalanceByAddressResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBalanceByAddressResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Balance != other.Balance) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Balance != 0UL) hash ^= Balance.GetHashCode(); + if (error_ != null) hash ^= Error.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 (Balance != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(Balance); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Balance != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Balance); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBalanceByAddressResponseMessage other) { + if (other == null) { + return; + } + if (other.Balance != 0UL) { + Balance = other.Balance; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8: { + Balance = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class GetBalancesByAddressesRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBalancesByAddressesRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[76]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalancesByAddressesRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalancesByAddressesRequestMessage(GetBalancesByAddressesRequestMessage other) : this() { + addresses_ = other.addresses_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalancesByAddressesRequestMessage Clone() { + return new GetBalancesByAddressesRequestMessage(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBalancesByAddressesRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBalancesByAddressesRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.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) { + addresses_.WriteTo(output, _repeated_addresses_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBalancesByAddressesRequestMessage other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + _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: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + } + } + } + + } + + public sealed partial class BalancesByAddressEntry : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BalancesByAddressEntry()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[77]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BalancesByAddressEntry() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BalancesByAddressEntry(BalancesByAddressEntry other) : this() { + address_ = other.address_; + balance_ = other.balance_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BalancesByAddressEntry Clone() { + return new BalancesByAddressEntry(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "balance" field. + public const int BalanceFieldNumber = 2; + private ulong balance_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong Balance { + get { return balance_; } + set { + balance_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BalancesByAddressEntry); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BalancesByAddressEntry other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + if (Balance != other.Balance) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.GetHashCode(); + if (Balance != 0UL) hash ^= Balance.GetHashCode(); + if (error_ != null) hash ^= Error.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + if (Balance != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(Balance); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + if (Balance != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(Balance); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BalancesByAddressEntry other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + if (other.Balance != 0UL) { + Balance = other.Balance; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + Address = input.ReadString(); + break; + } + case 16: { + Balance = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class GetBalancesByAddressesResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetBalancesByAddressesResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[78]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalancesByAddressesResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalancesByAddressesResponseMessage(GetBalancesByAddressesResponseMessage other) : this() { + entries_ = other.entries_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetBalancesByAddressesResponseMessage Clone() { + return new GetBalancesByAddressesResponseMessage(this); + } + + /// Field number for the "entries" field. + public const int EntriesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_entries_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.BalancesByAddressEntry.Parser); + private readonly pbc::RepeatedField entries_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Entries { + get { return entries_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetBalancesByAddressesResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetBalancesByAddressesResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!entries_.Equals(other.entries_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= entries_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + entries_.WriteTo(output, _repeated_entries_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += entries_.CalculateSize(_repeated_entries_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetBalancesByAddressesResponseMessage other) { + if (other == null) { + return; + } + entries_.Add(other.entries_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + entries_.AddEntriesFrom(input, _repeated_entries_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetVirtualSelectedParentBlueScoreRequestMessage requests the blue score of the current selected parent + /// of the virtual block. + /// + public sealed partial class GetVirtualSelectedParentBlueScoreRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetVirtualSelectedParentBlueScoreRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[79]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentBlueScoreRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentBlueScoreRequestMessage(GetVirtualSelectedParentBlueScoreRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentBlueScoreRequestMessage Clone() { + return new GetVirtualSelectedParentBlueScoreRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetVirtualSelectedParentBlueScoreRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetVirtualSelectedParentBlueScoreRequestMessage 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(GetVirtualSelectedParentBlueScoreRequestMessage 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 GetVirtualSelectedParentBlueScoreResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetVirtualSelectedParentBlueScoreResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[80]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentBlueScoreResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentBlueScoreResponseMessage(GetVirtualSelectedParentBlueScoreResponseMessage other) : this() { + blueScore_ = other.blueScore_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetVirtualSelectedParentBlueScoreResponseMessage Clone() { + return new GetVirtualSelectedParentBlueScoreResponseMessage(this); + } + + /// Field number for the "blueScore" field. + public const int BlueScoreFieldNumber = 1; + private ulong blueScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong BlueScore { + get { return blueScore_; } + set { + blueScore_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetVirtualSelectedParentBlueScoreResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetVirtualSelectedParentBlueScoreResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (BlueScore != other.BlueScore) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (BlueScore != 0UL) hash ^= BlueScore.GetHashCode(); + if (error_ != null) hash ^= Error.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 (BlueScore != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(BlueScore); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (BlueScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(BlueScore); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetVirtualSelectedParentBlueScoreResponseMessage other) { + if (other == null) { + return; + } + if (other.BlueScore != 0UL) { + BlueScore = other.BlueScore; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8: { + BlueScore = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// NotifyVirtualSelectedParentBlueScoreChangedRequestMessage registers this connection for + /// virtualSelectedParentBlueScoreChanged notifications. + /// + /// See: VirtualSelectedParentBlueScoreChangedNotificationMessage + /// + public sealed partial class NotifyVirtualSelectedParentBlueScoreChangedRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyVirtualSelectedParentBlueScoreChangedRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[81]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentBlueScoreChangedRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentBlueScoreChangedRequestMessage(NotifyVirtualSelectedParentBlueScoreChangedRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentBlueScoreChangedRequestMessage Clone() { + return new NotifyVirtualSelectedParentBlueScoreChangedRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyVirtualSelectedParentBlueScoreChangedRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyVirtualSelectedParentBlueScoreChangedRequestMessage 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(NotifyVirtualSelectedParentBlueScoreChangedRequestMessage 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 NotifyVirtualSelectedParentBlueScoreChangedResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyVirtualSelectedParentBlueScoreChangedResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[82]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentBlueScoreChangedResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentBlueScoreChangedResponseMessage(NotifyVirtualSelectedParentBlueScoreChangedResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualSelectedParentBlueScoreChangedResponseMessage Clone() { + return new NotifyVirtualSelectedParentBlueScoreChangedResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyVirtualSelectedParentBlueScoreChangedResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyVirtualSelectedParentBlueScoreChangedResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyVirtualSelectedParentBlueScoreChangedResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// VirtualSelectedParentBlueScoreChangedNotificationMessage is sent whenever the blue score + /// of the virtual's selected parent changes. + /// + /// See NotifyVirtualSelectedParentBlueScoreChangedRequestMessage + /// + public sealed partial class VirtualSelectedParentBlueScoreChangedNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new VirtualSelectedParentBlueScoreChangedNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[83]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualSelectedParentBlueScoreChangedNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualSelectedParentBlueScoreChangedNotificationMessage(VirtualSelectedParentBlueScoreChangedNotificationMessage other) : this() { + virtualSelectedParentBlueScore_ = other.virtualSelectedParentBlueScore_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualSelectedParentBlueScoreChangedNotificationMessage Clone() { + return new VirtualSelectedParentBlueScoreChangedNotificationMessage(this); + } + + /// Field number for the "virtualSelectedParentBlueScore" field. + public const int VirtualSelectedParentBlueScoreFieldNumber = 1; + private ulong virtualSelectedParentBlueScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong VirtualSelectedParentBlueScore { + get { return virtualSelectedParentBlueScore_; } + set { + virtualSelectedParentBlueScore_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as VirtualSelectedParentBlueScoreChangedNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(VirtualSelectedParentBlueScoreChangedNotificationMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (VirtualSelectedParentBlueScore != other.VirtualSelectedParentBlueScore) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (VirtualSelectedParentBlueScore != 0UL) hash ^= VirtualSelectedParentBlueScore.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 (VirtualSelectedParentBlueScore != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(VirtualSelectedParentBlueScore); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (VirtualSelectedParentBlueScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(VirtualSelectedParentBlueScore); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(VirtualSelectedParentBlueScoreChangedNotificationMessage other) { + if (other == null) { + return; + } + if (other.VirtualSelectedParentBlueScore != 0UL) { + VirtualSelectedParentBlueScore = other.VirtualSelectedParentBlueScore; + } + _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 8: { + VirtualSelectedParentBlueScore = input.ReadUInt64(); + break; + } + } + } + } + + } + + /// + /// NotifyVirtualDaaScoreChangedRequestMessage registers this connection for + /// virtualDaaScoreChanged notifications. + /// + /// See: VirtualDaaScoreChangedNotificationMessage + /// + public sealed partial class NotifyVirtualDaaScoreChangedRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyVirtualDaaScoreChangedRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[84]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualDaaScoreChangedRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualDaaScoreChangedRequestMessage(NotifyVirtualDaaScoreChangedRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualDaaScoreChangedRequestMessage Clone() { + return new NotifyVirtualDaaScoreChangedRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyVirtualDaaScoreChangedRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyVirtualDaaScoreChangedRequestMessage 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(NotifyVirtualDaaScoreChangedRequestMessage 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 NotifyVirtualDaaScoreChangedResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyVirtualDaaScoreChangedResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[85]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualDaaScoreChangedResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualDaaScoreChangedResponseMessage(NotifyVirtualDaaScoreChangedResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyVirtualDaaScoreChangedResponseMessage Clone() { + return new NotifyVirtualDaaScoreChangedResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyVirtualDaaScoreChangedResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyVirtualDaaScoreChangedResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyVirtualDaaScoreChangedResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// VirtualDaaScoreChangedNotificationMessage is sent whenever the DAA score + /// of the virtual changes. + /// + /// See NotifyVirtualDaaScoreChangedRequestMessage + /// + public sealed partial class VirtualDaaScoreChangedNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new VirtualDaaScoreChangedNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[86]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualDaaScoreChangedNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualDaaScoreChangedNotificationMessage(VirtualDaaScoreChangedNotificationMessage other) : this() { + virtualDaaScore_ = other.virtualDaaScore_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public VirtualDaaScoreChangedNotificationMessage Clone() { + return new VirtualDaaScoreChangedNotificationMessage(this); + } + + /// Field number for the "virtualDaaScore" field. + public const int VirtualDaaScoreFieldNumber = 1; + private ulong virtualDaaScore_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong VirtualDaaScore { + get { return virtualDaaScore_; } + set { + virtualDaaScore_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as VirtualDaaScoreChangedNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(VirtualDaaScoreChangedNotificationMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (VirtualDaaScore != other.VirtualDaaScore) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (VirtualDaaScore != 0UL) hash ^= VirtualDaaScore.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 (VirtualDaaScore != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(VirtualDaaScore); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (VirtualDaaScore != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(VirtualDaaScore); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(VirtualDaaScoreChangedNotificationMessage other) { + if (other == null) { + return; + } + if (other.VirtualDaaScore != 0UL) { + VirtualDaaScore = other.VirtualDaaScore; + } + _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 8: { + VirtualDaaScore = input.ReadUInt64(); + break; + } + } + } + } + + } + + /// + /// NotifyPruningPointUTXOSetOverrideRequestMessage registers this connection for + /// pruning point UTXO set override notifications. + /// + /// This call is only available when this kaspad was started with `--utxoindex` + /// + /// See: NotifyPruningPointUTXOSetOverrideResponseMessage + /// + public sealed partial class NotifyPruningPointUTXOSetOverrideRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyPruningPointUTXOSetOverrideRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[87]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyPruningPointUTXOSetOverrideRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyPruningPointUTXOSetOverrideRequestMessage(NotifyPruningPointUTXOSetOverrideRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyPruningPointUTXOSetOverrideRequestMessage Clone() { + return new NotifyPruningPointUTXOSetOverrideRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyPruningPointUTXOSetOverrideRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyPruningPointUTXOSetOverrideRequestMessage 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(NotifyPruningPointUTXOSetOverrideRequestMessage 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 NotifyPruningPointUTXOSetOverrideResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyPruningPointUTXOSetOverrideResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[88]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyPruningPointUTXOSetOverrideResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyPruningPointUTXOSetOverrideResponseMessage(NotifyPruningPointUTXOSetOverrideResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyPruningPointUTXOSetOverrideResponseMessage Clone() { + return new NotifyPruningPointUTXOSetOverrideResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyPruningPointUTXOSetOverrideResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyPruningPointUTXOSetOverrideResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyPruningPointUTXOSetOverrideResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// PruningPointUTXOSetOverrideNotificationMessage is sent whenever the UTXO index + /// resets due to pruning point change via IBD. + /// + /// See NotifyPruningPointUTXOSetOverrideRequestMessage + /// + public sealed partial class PruningPointUTXOSetOverrideNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new PruningPointUTXOSetOverrideNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[89]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointUTXOSetOverrideNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointUTXOSetOverrideNotificationMessage(PruningPointUTXOSetOverrideNotificationMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public PruningPointUTXOSetOverrideNotificationMessage Clone() { + return new PruningPointUTXOSetOverrideNotificationMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as PruningPointUTXOSetOverrideNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(PruningPointUTXOSetOverrideNotificationMessage 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(PruningPointUTXOSetOverrideNotificationMessage 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; + } + } + } + + } + + /// + /// StopNotifyingPruningPointUTXOSetOverrideRequestMessage unregisters this connection for + /// pruning point UTXO set override notifications. + /// + /// This call is only available when this kaspad was started with `--utxoindex` + /// + /// See: PruningPointUTXOSetOverrideNotificationMessage + /// + public sealed partial class StopNotifyingPruningPointUTXOSetOverrideRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StopNotifyingPruningPointUTXOSetOverrideRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[90]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingPruningPointUTXOSetOverrideRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingPruningPointUTXOSetOverrideRequestMessage(StopNotifyingPruningPointUTXOSetOverrideRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingPruningPointUTXOSetOverrideRequestMessage Clone() { + return new StopNotifyingPruningPointUTXOSetOverrideRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StopNotifyingPruningPointUTXOSetOverrideRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StopNotifyingPruningPointUTXOSetOverrideRequestMessage 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(StopNotifyingPruningPointUTXOSetOverrideRequestMessage 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 StopNotifyingPruningPointUTXOSetOverrideResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StopNotifyingPruningPointUTXOSetOverrideResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[91]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingPruningPointUTXOSetOverrideResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingPruningPointUTXOSetOverrideResponseMessage(StopNotifyingPruningPointUTXOSetOverrideResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public StopNotifyingPruningPointUTXOSetOverrideResponseMessage Clone() { + return new StopNotifyingPruningPointUTXOSetOverrideResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as StopNotifyingPruningPointUTXOSetOverrideResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(StopNotifyingPruningPointUTXOSetOverrideResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(StopNotifyingPruningPointUTXOSetOverrideResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// BanRequestMessage bans the given ip. + /// + public sealed partial class BanRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BanRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[92]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BanRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BanRequestMessage(BanRequestMessage other) : this() { + ip_ = other.ip_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BanRequestMessage Clone() { + return new BanRequestMessage(this); + } + + /// Field number for the "ip" field. + public const int IpFieldNumber = 1; + private string ip_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Ip { + get { return ip_; } + set { + ip_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BanRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BanRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Ip != other.Ip) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Ip.Length != 0) hash ^= Ip.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 (Ip.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Ip); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Ip.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Ip); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BanRequestMessage other) { + if (other == null) { + return; + } + if (other.Ip.Length != 0) { + Ip = other.Ip; + } + _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: { + Ip = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class BanResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new BanResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[93]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BanResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BanResponseMessage(BanResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public BanResponseMessage Clone() { + return new BanResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as BanResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(BanResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(BanResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// UnbanRequestMessage unbans the given ip. + /// + public sealed partial class UnbanRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UnbanRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[94]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnbanRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnbanRequestMessage(UnbanRequestMessage other) : this() { + ip_ = other.ip_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnbanRequestMessage Clone() { + return new UnbanRequestMessage(this); + } + + /// Field number for the "ip" field. + public const int IpFieldNumber = 1; + private string ip_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Ip { + get { return ip_; } + set { + ip_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UnbanRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UnbanRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Ip != other.Ip) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Ip.Length != 0) hash ^= Ip.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 (Ip.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Ip); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Ip.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Ip); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UnbanRequestMessage other) { + if (other == null) { + return; + } + if (other.Ip.Length != 0) { + Ip = other.Ip; + } + _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: { + Ip = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class UnbanResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new UnbanResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[95]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnbanResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnbanResponseMessage(UnbanResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public UnbanResponseMessage Clone() { + return new UnbanResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as UnbanResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(UnbanResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(UnbanResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// GetInfoRequestMessage returns info about the node. + /// + public sealed partial class GetInfoRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetInfoRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[96]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetInfoRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetInfoRequestMessage(GetInfoRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetInfoRequestMessage Clone() { + return new GetInfoRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetInfoRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetInfoRequestMessage 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(GetInfoRequestMessage 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 GetInfoResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetInfoResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[97]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetInfoResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetInfoResponseMessage(GetInfoResponseMessage other) : this() { + p2PId_ = other.p2PId_; + mempoolSize_ = other.mempoolSize_; + serverVersion_ = other.serverVersion_; + isUtxoIndexed_ = other.isUtxoIndexed_; + isSynced_ = other.isSynced_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetInfoResponseMessage Clone() { + return new GetInfoResponseMessage(this); + } + + /// Field number for the "p2pId" field. + public const int P2PIdFieldNumber = 1; + private string p2PId_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string P2PId { + get { return p2PId_; } + set { + p2PId_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "mempoolSize" field. + public const int MempoolSizeFieldNumber = 2; + private ulong mempoolSize_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong MempoolSize { + get { return mempoolSize_; } + set { + mempoolSize_ = value; + } + } + + /// Field number for the "serverVersion" field. + public const int ServerVersionFieldNumber = 3; + private string serverVersion_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string ServerVersion { + get { return serverVersion_; } + set { + serverVersion_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "isUtxoIndexed" field. + public const int IsUtxoIndexedFieldNumber = 4; + private bool isUtxoIndexed_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsUtxoIndexed { + get { return isUtxoIndexed_; } + set { + isUtxoIndexed_ = value; + } + } + + /// Field number for the "isSynced" field. + public const int IsSyncedFieldNumber = 5; + private bool isSynced_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IsSynced { + get { return isSynced_; } + set { + isSynced_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetInfoResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetInfoResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (P2PId != other.P2PId) return false; + if (MempoolSize != other.MempoolSize) return false; + if (ServerVersion != other.ServerVersion) return false; + if (IsUtxoIndexed != other.IsUtxoIndexed) return false; + if (IsSynced != other.IsSynced) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (P2PId.Length != 0) hash ^= P2PId.GetHashCode(); + if (MempoolSize != 0UL) hash ^= MempoolSize.GetHashCode(); + if (ServerVersion.Length != 0) hash ^= ServerVersion.GetHashCode(); + if (IsUtxoIndexed != false) hash ^= IsUtxoIndexed.GetHashCode(); + if (IsSynced != false) hash ^= IsSynced.GetHashCode(); + if (error_ != null) hash ^= Error.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 (P2PId.Length != 0) { + output.WriteRawTag(10); + output.WriteString(P2PId); + } + if (MempoolSize != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(MempoolSize); + } + if (ServerVersion.Length != 0) { + output.WriteRawTag(26); + output.WriteString(ServerVersion); + } + if (IsUtxoIndexed != false) { + output.WriteRawTag(32); + output.WriteBool(IsUtxoIndexed); + } + if (IsSynced != false) { + output.WriteRawTag(40); + output.WriteBool(IsSynced); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (P2PId.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(P2PId); + } + if (MempoolSize != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(MempoolSize); + } + if (ServerVersion.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(ServerVersion); + } + if (IsUtxoIndexed != false) { + size += 1 + 1; + } + if (IsSynced != false) { + size += 1 + 1; + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetInfoResponseMessage other) { + if (other == null) { + return; + } + if (other.P2PId.Length != 0) { + P2PId = other.P2PId; + } + if (other.MempoolSize != 0UL) { + MempoolSize = other.MempoolSize; + } + if (other.ServerVersion.Length != 0) { + ServerVersion = other.ServerVersion; + } + if (other.IsUtxoIndexed != false) { + IsUtxoIndexed = other.IsUtxoIndexed; + } + if (other.IsSynced != false) { + IsSynced = other.IsSynced; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + P2PId = input.ReadString(); + break; + } + case 16: { + MempoolSize = input.ReadUInt64(); + break; + } + case 26: { + ServerVersion = input.ReadString(); + break; + } + case 32: { + IsUtxoIndexed = input.ReadBool(); + break; + } + case 40: { + IsSynced = input.ReadBool(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class EstimateNetworkHashesPerSecondRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EstimateNetworkHashesPerSecondRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[98]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EstimateNetworkHashesPerSecondRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EstimateNetworkHashesPerSecondRequestMessage(EstimateNetworkHashesPerSecondRequestMessage other) : this() { + windowSize_ = other.windowSize_; + startHash_ = other.startHash_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EstimateNetworkHashesPerSecondRequestMessage Clone() { + return new EstimateNetworkHashesPerSecondRequestMessage(this); + } + + /// Field number for the "windowSize" field. + public const int WindowSizeFieldNumber = 1; + private uint windowSize_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public uint WindowSize { + get { return windowSize_; } + set { + windowSize_ = value; + } + } + + /// Field number for the "startHash" field. + public const int StartHashFieldNumber = 2; + private string startHash_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string StartHash { + get { return startHash_; } + set { + startHash_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EstimateNetworkHashesPerSecondRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EstimateNetworkHashesPerSecondRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (WindowSize != other.WindowSize) return false; + if (StartHash != other.StartHash) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (WindowSize != 0) hash ^= WindowSize.GetHashCode(); + if (StartHash.Length != 0) hash ^= StartHash.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 (WindowSize != 0) { + output.WriteRawTag(8); + output.WriteUInt32(WindowSize); + } + if (StartHash.Length != 0) { + output.WriteRawTag(18); + output.WriteString(StartHash); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (WindowSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(WindowSize); + } + if (StartHash.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(StartHash); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EstimateNetworkHashesPerSecondRequestMessage other) { + if (other == null) { + return; + } + if (other.WindowSize != 0) { + WindowSize = other.WindowSize; + } + if (other.StartHash.Length != 0) { + StartHash = other.StartHash; + } + _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 8: { + WindowSize = input.ReadUInt32(); + break; + } + case 18: { + StartHash = input.ReadString(); + break; + } + } + } + } + + } + + public sealed partial class EstimateNetworkHashesPerSecondResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new EstimateNetworkHashesPerSecondResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[99]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EstimateNetworkHashesPerSecondResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EstimateNetworkHashesPerSecondResponseMessage(EstimateNetworkHashesPerSecondResponseMessage other) : this() { + networkHashesPerSecond_ = other.networkHashesPerSecond_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public EstimateNetworkHashesPerSecondResponseMessage Clone() { + return new EstimateNetworkHashesPerSecondResponseMessage(this); + } + + /// Field number for the "networkHashesPerSecond" field. + public const int NetworkHashesPerSecondFieldNumber = 1; + private ulong networkHashesPerSecond_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong NetworkHashesPerSecond { + get { return networkHashesPerSecond_; } + set { + networkHashesPerSecond_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as EstimateNetworkHashesPerSecondResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(EstimateNetworkHashesPerSecondResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (NetworkHashesPerSecond != other.NetworkHashesPerSecond) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (NetworkHashesPerSecond != 0UL) hash ^= NetworkHashesPerSecond.GetHashCode(); + if (error_ != null) hash ^= Error.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 (NetworkHashesPerSecond != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(NetworkHashesPerSecond); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (NetworkHashesPerSecond != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(NetworkHashesPerSecond); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(EstimateNetworkHashesPerSecondResponseMessage other) { + if (other == null) { + return; + } + if (other.NetworkHashesPerSecond != 0UL) { + NetworkHashesPerSecond = other.NetworkHashesPerSecond; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8: { + NetworkHashesPerSecond = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// NotifyNewBlockTemplateRequestMessage registers this connection for + /// NewBlockTemplate notifications. + /// + /// See: NewBlockTemplateNotificationMessage + /// + public sealed partial class NotifyNewBlockTemplateRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyNewBlockTemplateRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[100]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyNewBlockTemplateRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyNewBlockTemplateRequestMessage(NotifyNewBlockTemplateRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyNewBlockTemplateRequestMessage Clone() { + return new NotifyNewBlockTemplateRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyNewBlockTemplateRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyNewBlockTemplateRequestMessage 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(NotifyNewBlockTemplateRequestMessage 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 NotifyNewBlockTemplateResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NotifyNewBlockTemplateResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[101]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyNewBlockTemplateResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyNewBlockTemplateResponseMessage(NotifyNewBlockTemplateResponseMessage other) : this() { + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NotifyNewBlockTemplateResponseMessage Clone() { + return new NotifyNewBlockTemplateResponseMessage(this); + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NotifyNewBlockTemplateResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NotifyNewBlockTemplateResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (error_ != null) hash ^= Error.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 (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(NotifyNewBlockTemplateResponseMessage other) { + if (other == null) { + return; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + /// + /// NewBlockTemplateNotificationMessage is sent whenever a new updated block template is + /// available for miners. + /// + /// See NotifyNewBlockTemplateRequestMessage + /// + public sealed partial class NewBlockTemplateNotificationMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new NewBlockTemplateNotificationMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[102]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewBlockTemplateNotificationMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewBlockTemplateNotificationMessage(NewBlockTemplateNotificationMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public NewBlockTemplateNotificationMessage Clone() { + return new NewBlockTemplateNotificationMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as NewBlockTemplateNotificationMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(NewBlockTemplateNotificationMessage 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(NewBlockTemplateNotificationMessage 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 MempoolEntryByAddress : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new MempoolEntryByAddress()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[103]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MempoolEntryByAddress() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MempoolEntryByAddress(MempoolEntryByAddress other) : this() { + address_ = other.address_; + sending_ = other.sending_.Clone(); + receiving_ = other.receiving_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public MempoolEntryByAddress Clone() { + return new MempoolEntryByAddress(this); + } + + /// Field number for the "address" field. + public const int AddressFieldNumber = 1; + private string address_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Address { + get { return address_; } + set { + address_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "sending" field. + public const int SendingFieldNumber = 2; + private static readonly pb::FieldCodec _repeated_sending_codec + = pb::FieldCodec.ForMessage(18, global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry.Parser); + private readonly pbc::RepeatedField sending_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Sending { + get { return sending_; } + } + + /// Field number for the "receiving" field. + public const int ReceivingFieldNumber = 3; + private static readonly pb::FieldCodec _repeated_receiving_codec + = pb::FieldCodec.ForMessage(26, global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntry.Parser); + private readonly pbc::RepeatedField receiving_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Receiving { + get { return receiving_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as MempoolEntryByAddress); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(MempoolEntryByAddress other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Address != other.Address) return false; + if(!sending_.Equals(other.sending_)) return false; + if(!receiving_.Equals(other.receiving_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Address.Length != 0) hash ^= Address.GetHashCode(); + hash ^= sending_.GetHashCode(); + hash ^= receiving_.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 (Address.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Address); + } + sending_.WriteTo(output, _repeated_sending_codec); + receiving_.WriteTo(output, _repeated_receiving_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Address.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Address); + } + size += sending_.CalculateSize(_repeated_sending_codec); + size += receiving_.CalculateSize(_repeated_receiving_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(MempoolEntryByAddress other) { + if (other == null) { + return; + } + if (other.Address.Length != 0) { + Address = other.Address; + } + sending_.Add(other.sending_); + receiving_.Add(other.receiving_); + _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: { + Address = input.ReadString(); + break; + } + case 18: { + sending_.AddEntriesFrom(input, _repeated_sending_codec); + break; + } + case 26: { + receiving_.AddEntriesFrom(input, _repeated_receiving_codec); + break; + } + } + } + } + + } + + public sealed partial class GetMempoolEntriesByAddressesRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMempoolEntriesByAddressesRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[104]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesByAddressesRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesByAddressesRequestMessage(GetMempoolEntriesByAddressesRequestMessage other) : this() { + addresses_ = other.addresses_.Clone(); + includeOrphanPool_ = other.includeOrphanPool_; + filterTransactionPool_ = other.filterTransactionPool_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesByAddressesRequestMessage Clone() { + return new GetMempoolEntriesByAddressesRequestMessage(this); + } + + /// Field number for the "addresses" field. + public const int AddressesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_addresses_codec + = pb::FieldCodec.ForString(10); + private readonly pbc::RepeatedField addresses_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Addresses { + get { return addresses_; } + } + + /// Field number for the "includeOrphanPool" field. + public const int IncludeOrphanPoolFieldNumber = 2; + private bool includeOrphanPool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool IncludeOrphanPool { + get { return includeOrphanPool_; } + set { + includeOrphanPool_ = value; + } + } + + /// Field number for the "filterTransactionPool" field. + public const int FilterTransactionPoolFieldNumber = 3; + private bool filterTransactionPool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool FilterTransactionPool { + get { return filterTransactionPool_; } + set { + filterTransactionPool_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetMempoolEntriesByAddressesRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetMempoolEntriesByAddressesRequestMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!addresses_.Equals(other.addresses_)) return false; + if (IncludeOrphanPool != other.IncludeOrphanPool) return false; + if (FilterTransactionPool != other.FilterTransactionPool) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= addresses_.GetHashCode(); + if (IncludeOrphanPool != false) hash ^= IncludeOrphanPool.GetHashCode(); + if (FilterTransactionPool != false) hash ^= FilterTransactionPool.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) { + addresses_.WriteTo(output, _repeated_addresses_codec); + if (IncludeOrphanPool != false) { + output.WriteRawTag(16); + output.WriteBool(IncludeOrphanPool); + } + if (FilterTransactionPool != false) { + output.WriteRawTag(24); + output.WriteBool(FilterTransactionPool); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += addresses_.CalculateSize(_repeated_addresses_codec); + if (IncludeOrphanPool != false) { + size += 1 + 1; + } + if (FilterTransactionPool != false) { + size += 1 + 1; + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetMempoolEntriesByAddressesRequestMessage other) { + if (other == null) { + return; + } + addresses_.Add(other.addresses_); + if (other.IncludeOrphanPool != false) { + IncludeOrphanPool = other.IncludeOrphanPool; + } + if (other.FilterTransactionPool != false) { + FilterTransactionPool = other.FilterTransactionPool; + } + _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: { + addresses_.AddEntriesFrom(input, _repeated_addresses_codec); + break; + } + case 16: { + IncludeOrphanPool = input.ReadBool(); + break; + } + case 24: { + FilterTransactionPool = input.ReadBool(); + break; + } + } + } + } + + } + + public sealed partial class GetMempoolEntriesByAddressesResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetMempoolEntriesByAddressesResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[105]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesByAddressesResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesByAddressesResponseMessage(GetMempoolEntriesByAddressesResponseMessage other) : this() { + entries_ = other.entries_.Clone(); + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetMempoolEntriesByAddressesResponseMessage Clone() { + return new GetMempoolEntriesByAddressesResponseMessage(this); + } + + /// Field number for the "entries" field. + public const int EntriesFieldNumber = 1; + private static readonly pb::FieldCodec _repeated_entries_codec + = pb::FieldCodec.ForMessage(10, global::Miningcore.Blockchain.Kaspa.Kaspad.MempoolEntryByAddress.Parser); + private readonly pbc::RepeatedField entries_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField Entries { + get { return entries_; } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetMempoolEntriesByAddressesResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetMempoolEntriesByAddressesResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!entries_.Equals(other.entries_)) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + hash ^= entries_.GetHashCode(); + if (error_ != null) hash ^= Error.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) { + entries_.WriteTo(output, _repeated_entries_codec); + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + size += entries_.CalculateSize(_repeated_entries_codec); + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetMempoolEntriesByAddressesResponseMessage other) { + if (other == null) { + return; + } + entries_.Add(other.entries_); + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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: { + entries_.AddEntriesFrom(input, _repeated_entries_codec); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + public sealed partial class GetCoinSupplyRequestMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetCoinSupplyRequestMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[106]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCoinSupplyRequestMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCoinSupplyRequestMessage(GetCoinSupplyRequestMessage other) : this() { + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCoinSupplyRequestMessage Clone() { + return new GetCoinSupplyRequestMessage(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetCoinSupplyRequestMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetCoinSupplyRequestMessage 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(GetCoinSupplyRequestMessage 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 GetCoinSupplyResponseMessage : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new GetCoinSupplyResponseMessage()); + 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.Kaspad.RpcReflection.Descriptor.MessageTypes[107]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCoinSupplyResponseMessage() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCoinSupplyResponseMessage(GetCoinSupplyResponseMessage other) : this() { + maxSompi_ = other.maxSompi_; + circulatingSompi_ = other.circulatingSompi_; + error_ = other.error_ != null ? other.error_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public GetCoinSupplyResponseMessage Clone() { + return new GetCoinSupplyResponseMessage(this); + } + + /// Field number for the "maxSompi" field. + public const int MaxSompiFieldNumber = 1; + private ulong maxSompi_; + /// + /// note: this is a hard coded maxSupply, actual maxSupply is expected to deviate by upto -5%, but cannot be measured exactly. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong MaxSompi { + get { return maxSompi_; } + set { + maxSompi_ = value; + } + } + + /// Field number for the "circulatingSompi" field. + public const int CirculatingSompiFieldNumber = 2; + private ulong circulatingSompi_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public ulong CirculatingSompi { + get { return circulatingSompi_; } + set { + circulatingSompi_ = value; + } + } + + /// Field number for the "error" field. + public const int ErrorFieldNumber = 1000; + private global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError error_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError Error { + get { return error_; } + set { + error_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as GetCoinSupplyResponseMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(GetCoinSupplyResponseMessage other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (MaxSompi != other.MaxSompi) return false; + if (CirculatingSompi != other.CirculatingSompi) return false; + if (!object.Equals(Error, other.Error)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (MaxSompi != 0UL) hash ^= MaxSompi.GetHashCode(); + if (CirculatingSompi != 0UL) hash ^= CirculatingSompi.GetHashCode(); + if (error_ != null) hash ^= Error.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 (MaxSompi != 0UL) { + output.WriteRawTag(8); + output.WriteUInt64(MaxSompi); + } + if (CirculatingSompi != 0UL) { + output.WriteRawTag(16); + output.WriteUInt64(CirculatingSompi); + } + if (error_ != null) { + output.WriteRawTag(194, 62); + output.WriteMessage(Error); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (MaxSompi != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(MaxSompi); + } + if (CirculatingSompi != 0UL) { + size += 1 + pb::CodedOutputStream.ComputeUInt64Size(CirculatingSompi); + } + if (error_ != null) { + size += 2 + pb::CodedOutputStream.ComputeMessageSize(Error); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(GetCoinSupplyResponseMessage other) { + if (other == null) { + return; + } + if (other.MaxSompi != 0UL) { + MaxSompi = other.MaxSompi; + } + if (other.CirculatingSompi != 0UL) { + CirculatingSompi = other.CirculatingSompi; + } + if (other.error_ != null) { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + Error.MergeFrom(other.Error); + } + _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 8: { + MaxSompi = input.ReadUInt64(); + break; + } + case 16: { + CirculatingSompi = input.ReadUInt64(); + break; + } + case 8002: { + if (error_ == null) { + Error = new global::Miningcore.Blockchain.Kaspa.Kaspad.RPCError(); + } + input.ReadMessage(Error); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/messages.proto b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/messages.proto new file mode 100644 index 000000000..84c6961de --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/messages.proto @@ -0,0 +1,152 @@ +// https://raw.githubusercontent.com/kaspanet/kaspad/master/infrastructure/network/netadapter/server/grpcserver/protowire/messages.proto +syntax = "proto3"; + +option csharp_namespace = "Miningcore.Blockchain.Kaspa.Kaspad"; +package protowire; + +import "p2p.proto"; +import "rpc.proto"; + +message KaspadMessage { + oneof payload { + AddressesMessage addresses = 1; + BlockMessage block = 2; + TransactionMessage transaction = 3; + BlockLocatorMessage blockLocator = 5; + RequestAddressesMessage requestAddresses = 6; + RequestRelayBlocksMessage requestRelayBlocks = 10; + RequestTransactionsMessage requestTransactions = 12; + BlockMessage ibdBlock = 13; + InvRelayBlockMessage invRelayBlock = 14; + InvTransactionsMessage invTransactions = 15; + PingMessage ping = 16; + PongMessage pong = 17; + VerackMessage verack = 19; + VersionMessage version = 20; + TransactionNotFoundMessage transactionNotFound = 21; + RejectMessage reject = 22; + PruningPointUtxoSetChunkMessage pruningPointUtxoSetChunk = 25; + RequestIBDBlocksMessage requestIBDBlocks = 26; + UnexpectedPruningPointMessage unexpectedPruningPoint = 27; + IbdBlockLocatorMessage ibdBlockLocator = 30; + IbdBlockLocatorHighestHashMessage ibdBlockLocatorHighestHash = 31; + RequestNextPruningPointUtxoSetChunkMessage requestNextPruningPointUtxoSetChunk = 33; + DonePruningPointUtxoSetChunksMessage donePruningPointUtxoSetChunks = 34; + IbdBlockLocatorHighestHashNotFoundMessage ibdBlockLocatorHighestHashNotFound = 35; + BlockWithTrustedDataMessage blockWithTrustedData = 36; + DoneBlocksWithTrustedDataMessage doneBlocksWithTrustedData = 37; + RequestPruningPointAndItsAnticoneMessage requestPruningPointAndItsAnticone = 40; + BlockHeadersMessage blockHeaders = 41; + RequestNextHeadersMessage requestNextHeaders = 42; + DoneHeadersMessage DoneHeaders = 43; + RequestPruningPointUTXOSetMessage requestPruningPointUTXOSet = 44; + RequestHeadersMessage requestHeaders = 45; + RequestBlockLocatorMessage requestBlockLocator = 46; + PruningPointsMessage pruningPoints = 47; + RequestPruningPointProofMessage requestPruningPointProof = 48; + PruningPointProofMessage pruningPointProof = 49; + ReadyMessage ready = 50; + BlockWithTrustedDataV4Message blockWithTrustedDataV4 = 51; + TrustedDataMessage trustedData = 52; + RequestIBDChainBlockLocatorMessage requestIBDChainBlockLocator = 53; + IbdChainBlockLocatorMessage ibdChainBlockLocator = 54; + RequestAnticoneMessage requestAnticone = 55; + RequestNextPruningPointAndItsAnticoneBlocksMessage requestNextPruningPointAndItsAnticoneBlocks = 56; + + GetCurrentNetworkRequestMessage getCurrentNetworkRequest = 1001; + GetCurrentNetworkResponseMessage getCurrentNetworkResponse = 1002; + SubmitBlockRequestMessage submitBlockRequest = 1003; + SubmitBlockResponseMessage submitBlockResponse = 1004; + GetBlockTemplateRequestMessage getBlockTemplateRequest = 1005; + GetBlockTemplateResponseMessage getBlockTemplateResponse = 1006; + NotifyBlockAddedRequestMessage notifyBlockAddedRequest = 1007; + NotifyBlockAddedResponseMessage notifyBlockAddedResponse = 1008; + BlockAddedNotificationMessage blockAddedNotification = 1009; + GetPeerAddressesRequestMessage getPeerAddressesRequest = 1010; + GetPeerAddressesResponseMessage getPeerAddressesResponse = 1011; + GetSelectedTipHashRequestMessage getSelectedTipHashRequest = 1012; + GetSelectedTipHashResponseMessage getSelectedTipHashResponse = 1013; + GetMempoolEntryRequestMessage getMempoolEntryRequest = 1014; + GetMempoolEntryResponseMessage getMempoolEntryResponse = 1015; + GetConnectedPeerInfoRequestMessage getConnectedPeerInfoRequest = 1016; + GetConnectedPeerInfoResponseMessage getConnectedPeerInfoResponse = 1017; + AddPeerRequestMessage addPeerRequest = 1018; + AddPeerResponseMessage addPeerResponse = 1019; + SubmitTransactionRequestMessage submitTransactionRequest = 1020; + SubmitTransactionResponseMessage submitTransactionResponse = 1021; + NotifyVirtualSelectedParentChainChangedRequestMessage notifyVirtualSelectedParentChainChangedRequest = 1022; + NotifyVirtualSelectedParentChainChangedResponseMessage notifyVirtualSelectedParentChainChangedResponse = 1023; + VirtualSelectedParentChainChangedNotificationMessage virtualSelectedParentChainChangedNotification = 1024; + GetBlockRequestMessage getBlockRequest = 1025; + GetBlockResponseMessage getBlockResponse = 1026; + GetSubnetworkRequestMessage getSubnetworkRequest = 1027; + GetSubnetworkResponseMessage getSubnetworkResponse = 1028; + GetVirtualSelectedParentChainFromBlockRequestMessage getVirtualSelectedParentChainFromBlockRequest = 1029; + GetVirtualSelectedParentChainFromBlockResponseMessage getVirtualSelectedParentChainFromBlockResponse = 1030; + GetBlocksRequestMessage getBlocksRequest = 1031; + GetBlocksResponseMessage getBlocksResponse = 1032; + GetBlockCountRequestMessage getBlockCountRequest = 1033; + GetBlockCountResponseMessage getBlockCountResponse = 1034; + GetBlockDagInfoRequestMessage getBlockDagInfoRequest = 1035; + GetBlockDagInfoResponseMessage getBlockDagInfoResponse = 1036; + ResolveFinalityConflictRequestMessage resolveFinalityConflictRequest = 1037; + ResolveFinalityConflictResponseMessage resolveFinalityConflictResponse = 1038; + NotifyFinalityConflictsRequestMessage notifyFinalityConflictsRequest = 1039; + NotifyFinalityConflictsResponseMessage notifyFinalityConflictsResponse = 1040; + FinalityConflictNotificationMessage finalityConflictNotification = 1041; + FinalityConflictResolvedNotificationMessage finalityConflictResolvedNotification = 1042; + GetMempoolEntriesRequestMessage getMempoolEntriesRequest = 1043; + GetMempoolEntriesResponseMessage getMempoolEntriesResponse = 1044; + ShutDownRequestMessage shutDownRequest = 1045; + ShutDownResponseMessage shutDownResponse = 1046; + GetHeadersRequestMessage getHeadersRequest = 1047; + GetHeadersResponseMessage getHeadersResponse = 1048; + NotifyUtxosChangedRequestMessage notifyUtxosChangedRequest = 1049; + NotifyUtxosChangedResponseMessage notifyUtxosChangedResponse = 1050; + UtxosChangedNotificationMessage utxosChangedNotification = 1051; + GetUtxosByAddressesRequestMessage getUtxosByAddressesRequest = 1052; + GetUtxosByAddressesResponseMessage getUtxosByAddressesResponse = 1053; + GetVirtualSelectedParentBlueScoreRequestMessage getVirtualSelectedParentBlueScoreRequest = 1054; + GetVirtualSelectedParentBlueScoreResponseMessage getVirtualSelectedParentBlueScoreResponse = 1055; + NotifyVirtualSelectedParentBlueScoreChangedRequestMessage notifyVirtualSelectedParentBlueScoreChangedRequest = 1056; + NotifyVirtualSelectedParentBlueScoreChangedResponseMessage notifyVirtualSelectedParentBlueScoreChangedResponse = 1057; + VirtualSelectedParentBlueScoreChangedNotificationMessage virtualSelectedParentBlueScoreChangedNotification = 1058; + BanRequestMessage banRequest = 1059; + BanResponseMessage banResponse = 1060; + UnbanRequestMessage unbanRequest = 1061; + UnbanResponseMessage unbanResponse = 1062; + GetInfoRequestMessage getInfoRequest = 1063; + GetInfoResponseMessage getInfoResponse = 1064; + StopNotifyingUtxosChangedRequestMessage stopNotifyingUtxosChangedRequest = 1065; + StopNotifyingUtxosChangedResponseMessage stopNotifyingUtxosChangedResponse = 1066; + NotifyPruningPointUTXOSetOverrideRequestMessage notifyPruningPointUTXOSetOverrideRequest = 1067; + NotifyPruningPointUTXOSetOverrideResponseMessage notifyPruningPointUTXOSetOverrideResponse = 1068; + PruningPointUTXOSetOverrideNotificationMessage pruningPointUTXOSetOverrideNotification = 1069; + StopNotifyingPruningPointUTXOSetOverrideRequestMessage stopNotifyingPruningPointUTXOSetOverrideRequest = 1070; + StopNotifyingPruningPointUTXOSetOverrideResponseMessage stopNotifyingPruningPointUTXOSetOverrideResponse = 1071; + EstimateNetworkHashesPerSecondRequestMessage estimateNetworkHashesPerSecondRequest = 1072; + EstimateNetworkHashesPerSecondResponseMessage estimateNetworkHashesPerSecondResponse = 1073; + NotifyVirtualDaaScoreChangedRequestMessage notifyVirtualDaaScoreChangedRequest = 1074; + NotifyVirtualDaaScoreChangedResponseMessage notifyVirtualDaaScoreChangedResponse = 1075; + VirtualDaaScoreChangedNotificationMessage virtualDaaScoreChangedNotification = 1076; + GetBalanceByAddressRequestMessage getBalanceByAddressRequest = 1077; + GetBalanceByAddressResponseMessage getBalanceByAddressResponse = 1078; + GetBalancesByAddressesRequestMessage getBalancesByAddressesRequest = 1079; + GetBalancesByAddressesResponseMessage getBalancesByAddressesResponse = 1080; + NotifyNewBlockTemplateRequestMessage notifyNewBlockTemplateRequest = 1081; + NotifyNewBlockTemplateResponseMessage notifyNewBlockTemplateResponse = 1082; + NewBlockTemplateNotificationMessage newBlockTemplateNotification = 1083; + GetMempoolEntriesByAddressesRequestMessage getMempoolEntriesByAddressesRequest = 1084; + GetMempoolEntriesByAddressesResponseMessage getMempoolEntriesByAddressesResponse = 1085; + GetCoinSupplyRequestMessage getCoinSupplyRequest = 1086; + GetCoinSupplyResponseMessage getCoinSupplyResponse= 1087; + } +} + +service P2P { + rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} +} + +service RPC { + rpc MessageStream (stream KaspadMessage) returns (stream KaspadMessage) {} +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto new file mode 100644 index 000000000..6527082d9 --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/p2p.proto @@ -0,0 +1,291 @@ +// https://raw.githubusercontent.com/kaspanet/kaspad/master/infrastructure/network/netadapter/server/grpcserver/protowire/p2p.proto +syntax = "proto3"; + +option csharp_namespace = "Miningcore.Blockchain.Kaspa.Kaspad"; +package protowire; + +message RequestAddressesMessage{ + bool includeAllSubnetworks = 1; + SubnetworkId subnetworkId = 2; +} + +message AddressesMessage{ + repeated NetAddress addressList = 1; +} + +message NetAddress{ + int64 timestamp = 1; + bytes ip = 3; + uint32 port = 4; +} + +message SubnetworkId{ + bytes bytes = 1; +} + +message TransactionMessage{ + uint32 version = 1; + repeated TransactionInput inputs = 2; + repeated TransactionOutput outputs = 3; + uint64 lockTime = 4; + SubnetworkId subnetworkId = 5; + uint64 gas = 6; + bytes payload = 8; +} + +message TransactionInput{ + Outpoint previousOutpoint = 1; + bytes signatureScript = 2; + uint64 sequence = 3; + uint32 sigOpCount = 4; +} + +message Outpoint{ + TransactionId transactionId = 1; + uint32 index = 2; +} + +message TransactionId{ + bytes bytes = 1; +} +message ScriptPublicKey { + bytes script = 1; + uint32 version = 2; +} + +message TransactionOutput{ + uint64 value = 1; + ScriptPublicKey scriptPublicKey = 2; +} + +message BlockMessage{ + BlockHeader header = 1; + repeated TransactionMessage transactions = 2; +} + +message BlockHeader{ + uint32 version = 1; + repeated BlockLevelParents parents = 12; + Hash hashMerkleRoot = 3; + Hash acceptedIdMerkleRoot = 4; + Hash utxoCommitment = 5; + int64 timestamp = 6; + uint32 bits = 7; + uint64 nonce = 8; + uint64 daaScore = 9; + bytes blueWork = 10; + Hash pruningPoint = 14; + uint64 blueScore = 13; +} + +message BlockLevelParents { + repeated Hash parentHashes = 1; +} + +message Hash{ + bytes bytes = 1; +} + +message RequestBlockLocatorMessage{ + Hash highHash = 1; + uint32 limit = 2; +} + +message BlockLocatorMessage{ + repeated Hash hashes = 1; +} + +message RequestHeadersMessage{ + Hash lowHash = 1; + Hash highHash = 2; +} + +message RequestNextHeadersMessage{ +} + +message DoneHeadersMessage{ +} + +message RequestRelayBlocksMessage{ + repeated Hash hashes = 1; +} + +message RequestTransactionsMessage { + repeated TransactionId ids = 1; +} + +message TransactionNotFoundMessage{ + TransactionId id = 1; +} + +message InvRelayBlockMessage{ + Hash hash = 1; +} + +message InvTransactionsMessage{ + repeated TransactionId ids = 1; +} + +message PingMessage{ + uint64 nonce = 1; +} + +message PongMessage{ + uint64 nonce = 1; +} + +message VerackMessage{ +} + +message VersionMessage{ + uint32 protocolVersion = 1; + uint64 services = 2; + int64 timestamp = 3; + NetAddress address = 4; + bytes id = 5; + string userAgent = 6; + bool disableRelayTx = 8; + SubnetworkId subnetworkId = 9; + string network = 10; +} + +message RejectMessage{ + string reason = 1; +} + +message RequestPruningPointUTXOSetMessage{ + Hash pruningPointHash = 1; +} + +message PruningPointUtxoSetChunkMessage{ + repeated OutpointAndUtxoEntryPair outpointAndUtxoEntryPairs = 1; +} + +message OutpointAndUtxoEntryPair{ + Outpoint outpoint = 1; + UtxoEntry utxoEntry = 2; +} + +message UtxoEntry { + uint64 amount = 1; + ScriptPublicKey scriptPublicKey = 2; + uint64 blockDaaScore = 3; + bool isCoinbase = 4; +} + +message RequestNextPruningPointUtxoSetChunkMessage { +} + +message DonePruningPointUtxoSetChunksMessage { +} + +message RequestIBDBlocksMessage{ + repeated Hash hashes = 1; +} + +message UnexpectedPruningPointMessage{ +} + +message IbdBlockLocatorMessage { + Hash targetHash = 1; + repeated Hash blockLocatorHashes = 2; +} + +message RequestIBDChainBlockLocatorMessage{ + Hash lowHash = 1; + Hash highHash = 2; +} + +message IbdChainBlockLocatorMessage { + repeated Hash blockLocatorHashes = 1; +} + +message RequestAnticoneMessage{ + Hash blockHash = 1; + Hash contextHash = 2; +} + +message IbdBlockLocatorHighestHashMessage { + Hash highestHash = 1; +} + +message IbdBlockLocatorHighestHashNotFoundMessage { +} + +message BlockHeadersMessage { + repeated BlockHeader blockHeaders = 1; +} + +message RequestPruningPointAndItsAnticoneMessage { +} + +message RequestNextPruningPointAndItsAnticoneBlocksMessage{ +} + +message BlockWithTrustedDataMessage { + BlockMessage block = 1; + uint64 daaScore = 2; + repeated DaaBlock daaWindow = 3; + repeated BlockGhostdagDataHashPair ghostdagData = 4; +} + +message DaaBlock { + BlockMessage block = 3; + GhostdagData ghostdagData = 2; +} + +message DaaBlockV4 { + BlockHeader header = 1; + GhostdagData ghostdagData = 2; +} + +message BlockGhostdagDataHashPair { + Hash hash = 1; + GhostdagData ghostdagData = 2; +} + +message GhostdagData { + uint64 blueScore = 1; + bytes blueWork = 2; + Hash selectedParent = 3; + repeated Hash mergeSetBlues = 4; + repeated Hash mergeSetReds = 5; + repeated BluesAnticoneSizes bluesAnticoneSizes = 6; +} + +message BluesAnticoneSizes { + Hash blueHash = 1; + uint32 anticoneSize = 2; +} + +message DoneBlocksWithTrustedDataMessage { +} + +message PruningPointsMessage { + repeated BlockHeader headers = 1; +} + +message RequestPruningPointProofMessage { +} + +message PruningPointProofMessage { + repeated PruningPointProofHeaderArray headers = 1; +} + +message PruningPointProofHeaderArray { + repeated BlockHeader headers = 1; +} + +message ReadyMessage { +} + +message BlockWithTrustedDataV4Message { + BlockMessage block = 1; + repeated uint64 daaWindowIndices = 2; + repeated uint64 ghostdagDataIndices = 3; +} + +message TrustedDataMessage { + repeated DaaBlockV4 daaWindow = 1; + repeated BlockGhostdagDataHashPair ghostdagData = 2; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto new file mode 100644 index 000000000..91eeb6f5a --- /dev/null +++ b/src/Miningcore/Blockchain/Kaspa/RPC/Kaspad/rpc.proto @@ -0,0 +1,724 @@ +// https://raw.githubusercontent.com/kaspanet/kaspad/master/infrastructure/network/netadapter/server/grpcserver/protowire/rpc.proto +// RPC-related types. Request messages, response messages, and dependant types. +// +// Clients are expected to build RequestMessages and wrap them in KaspadMessage. (see messages.proto) +// +// Having received a RequestMessage, (wrapped in a KaspadMessage) the RPC server will respond with a +// ResponseMessage (likewise wrapped in a KaspadMessage) respective to the original RequestMessage. +// +// **IMPORTANT:** This API is a work in progress and is subject to break between versions. +// +syntax = "proto3"; + +option csharp_namespace = "Miningcore.Blockchain.Kaspa.Kaspad"; +package protowire; + +// RPCError represents a generic non-internal error. +// +// Receivers of any ResponseMessage are expected to check whether its error field is not null. +message RPCError{ + string message = 1; +} + +message RpcBlock { + RpcBlockHeader header = 1; + repeated RpcTransaction transactions = 2; + RpcBlockVerboseData verboseData = 3; +} + +message RpcBlockHeader { + uint32 version = 1; + repeated RpcBlockLevelParents parents = 12; + string hashMerkleRoot = 3; + string acceptedIdMerkleRoot = 4; + string utxoCommitment = 5; + int64 timestamp = 6; + uint32 bits = 7; + uint64 nonce = 8; + uint64 daaScore = 9; + string blueWork = 10; + string pruningPoint = 14; + uint64 blueScore = 13; +} + +message RpcBlockLevelParents { + repeated string parentHashes = 1; +} + +message RpcBlockVerboseData{ + string hash = 1; + double difficulty = 11; + string selectedParentHash = 13; + repeated string transactionIds = 14; + bool isHeaderOnly = 15; + uint64 blueScore = 16; + repeated string childrenHashes = 17; + repeated string mergeSetBluesHashes = 18; + repeated string mergeSetRedsHashes = 19; + bool isChainBlock = 20; +} + +message RpcTransaction { + uint32 version = 1; + repeated RpcTransactionInput inputs = 2; + repeated RpcTransactionOutput outputs = 3; + uint64 lockTime = 4; + string subnetworkId = 5; + uint64 gas = 6; + string payload = 8; + RpcTransactionVerboseData verboseData = 9; +} + +message RpcTransactionInput { + RpcOutpoint previousOutpoint = 1; + string signatureScript = 2; + uint64 sequence = 3; + uint32 sigOpCount = 5; + RpcTransactionInputVerboseData verboseData = 4; +} + +message RpcScriptPublicKey { + uint32 version = 1; + string scriptPublicKey = 2; +} + +message RpcTransactionOutput { + uint64 amount = 1; + RpcScriptPublicKey scriptPublicKey = 2; + RpcTransactionOutputVerboseData verboseData = 3; +} + +message RpcOutpoint { + string transactionId = 1; + uint32 index = 2; +} + +message RpcUtxoEntry { + uint64 amount = 1; + RpcScriptPublicKey scriptPublicKey = 2; + uint64 blockDaaScore = 3; + bool isCoinbase = 4; +} + +message RpcTransactionVerboseData{ + string transactionId = 1; + string hash = 2; + uint64 mass = 4; + string blockHash = 12; + uint64 blockTime = 14; +} + +message RpcTransactionInputVerboseData{ +} + +message RpcTransactionOutputVerboseData{ + string scriptPublicKeyType = 5; + string scriptPublicKeyAddress = 6; +} + +// GetCurrentNetworkRequestMessage requests the network kaspad is currently running against. +// +// Possible networks are: Mainnet, Testnet, Simnet, Devnet +message GetCurrentNetworkRequestMessage{ +} + +message GetCurrentNetworkResponseMessage{ + string currentNetwork = 1; + RPCError error = 1000; +} + +// SubmitBlockRequestMessage requests to submit a block into the DAG. +// Blocks are generally expected to have been generated using the getBlockTemplate call. +// +// See: GetBlockTemplateRequestMessage +message SubmitBlockRequestMessage{ + RpcBlock block = 2; + bool allowNonDAABlocks = 3; +} + +message SubmitBlockResponseMessage{ + enum RejectReason { + NONE = 0; + BLOCK_INVALID = 1; + IS_IN_IBD = 2; + } + RejectReason rejectReason = 1; + RPCError error = 1000; +} + +// GetBlockTemplateRequestMessage requests a current block template. +// Callers are expected to solve the block template and submit it using the submitBlock call +// +// See: SubmitBlockRequestMessage +message GetBlockTemplateRequestMessage{ + // Which kaspa address should the coinbase block reward transaction pay into + string payAddress = 1; + string extraData = 2; +} + +message GetBlockTemplateResponseMessage{ + RpcBlock block = 3; + + // Whether kaspad thinks that it's synced. + // Callers are discouraged (but not forbidden) from solving blocks when kaspad is not synced. + // That is because when kaspad isn't in sync with the rest of the network there's a high + // chance the block will never be accepted, thus the solving effort would have been wasted. + bool isSynced = 2; + + RPCError error = 1000; +} + +// NotifyBlockAddedRequestMessage registers this connection for blockAdded notifications. +// +// See: BlockAddedNotificationMessage +message NotifyBlockAddedRequestMessage{ +} + +message NotifyBlockAddedResponseMessage{ + RPCError error = 1000; +} + +// BlockAddedNotificationMessage is sent whenever a blocks has been added (NOT accepted) +// into the DAG. +// +// See: NotifyBlockAddedRequestMessage +message BlockAddedNotificationMessage{ + RpcBlock block = 3; +} + +// GetPeerAddressesRequestMessage requests the list of known kaspad addresses in the +// current network. (mainnet, testnet, etc.) +message GetPeerAddressesRequestMessage{ +} + +message GetPeerAddressesResponseMessage{ + repeated GetPeerAddressesKnownAddressMessage addresses = 1; + repeated GetPeerAddressesKnownAddressMessage bannedAddresses = 2; + RPCError error = 1000; +} + +message GetPeerAddressesKnownAddressMessage { + string Addr = 1; +} + +// GetSelectedTipHashRequestMessage requests the hash of the current virtual's +// selected parent. +message GetSelectedTipHashRequestMessage{ +} + +message GetSelectedTipHashResponseMessage{ + string selectedTipHash = 1; + RPCError error = 1000; +} + +// GetMempoolEntryRequestMessage requests information about a specific transaction +// in the mempool. +message GetMempoolEntryRequestMessage{ + // The transaction's TransactionID. + string txId = 1; + bool includeOrphanPool = 2; + bool filterTransactionPool = 3; +} + +message GetMempoolEntryResponseMessage{ + MempoolEntry entry = 1; + + RPCError error = 1000; +} + +// GetMempoolEntriesRequestMessage requests information about all the transactions +// currently in the mempool. +message GetMempoolEntriesRequestMessage{ + bool includeOrphanPool = 1; + bool filterTransactionPool = 2; +} + +message GetMempoolEntriesResponseMessage{ + repeated MempoolEntry entries = 1; + + RPCError error = 1000; +} + +message MempoolEntry{ + uint64 fee = 1; + RpcTransaction transaction = 3; + bool isOrphan = 4; +} + +// GetConnectedPeerInfoRequestMessage requests information about all the p2p peers +// currently connected to this kaspad. +message GetConnectedPeerInfoRequestMessage{ +} + +message GetConnectedPeerInfoResponseMessage{ + repeated GetConnectedPeerInfoMessage infos = 1; + RPCError error = 1000; +} + +message GetConnectedPeerInfoMessage{ + string id = 1; + string address = 2; + + // How long did the last ping/pong exchange take + int64 lastPingDuration = 3; + + // Whether this kaspad initiated the connection + bool isOutbound = 6; + int64 timeOffset = 7; + string userAgent = 8; + + // The protocol version that this peer claims to support + uint32 advertisedProtocolVersion = 9; + + // The timestamp of when this peer connected to this kaspad + int64 timeConnected = 10; + + // Whether this peer is the IBD peer (if IBD is running) + bool isIbdPeer = 11; +} + +// AddPeerRequestMessage adds a peer to kaspad's outgoing connection list. +// This will, in most cases, result in kaspad connecting to said peer. +message AddPeerRequestMessage{ + string address = 1; + + // Whether to keep attempting to connect to this peer after disconnection + bool isPermanent = 2; +} + +message AddPeerResponseMessage{ + RPCError error = 1000; +} + +// SubmitTransactionRequestMessage submits a transaction to the mempool +message SubmitTransactionRequestMessage{ + RpcTransaction transaction = 1; + bool allowOrphan = 2; +} + +message SubmitTransactionResponseMessage{ + // The transaction ID of the submitted transaction + string transactionId = 1; + + RPCError error = 1000; +} + +// NotifyVirtualSelectedParentChainChangedRequestMessage registers this connection for virtualSelectedParentChainChanged notifications. +// +// See: VirtualSelectedParentChainChangedNotificationMessage +message NotifyVirtualSelectedParentChainChangedRequestMessage{ + bool includeAcceptedTransactionIds = 1; +} + +message NotifyVirtualSelectedParentChainChangedResponseMessage{ + RPCError error = 1000; +} + +// VirtualSelectedParentChainChangedNotificationMessage is sent whenever the DAG's selected parent +// chain had changed. +// +// See: NotifyVirtualSelectedParentChainChangedRequestMessage +message VirtualSelectedParentChainChangedNotificationMessage{ + // The chain blocks that were removed, in high-to-low order + repeated string removedChainBlockHashes = 1; + + // The chain blocks that were added, in low-to-high order + repeated string addedChainBlockHashes = 3; + + // Will be filled only if `includeAcceptedTransactionIds = true` in the notify request. + repeated AcceptedTransactionIds acceptedTransactionIds = 2; +} + +// GetBlockRequestMessage requests information about a specific block +message GetBlockRequestMessage{ + // The hash of the requested block + string hash = 1; + + // Whether to include transaction data in the response + bool includeTransactions = 3; +} + +message GetBlockResponseMessage{ + RpcBlock block = 3; + RPCError error = 1000; +} + +// GetSubnetworkRequestMessage requests information about a specific subnetwork +// +// Currently unimplemented +message GetSubnetworkRequestMessage{ + string subnetworkId = 1; +} + +message GetSubnetworkResponseMessage{ + uint64 gasLimit = 1; + RPCError error = 1000; +} + +// GetVirtualSelectedParentChainFromBlockRequestMessage requests the virtual selected +// parent chain from some startHash to this kaspad's current virtual +message GetVirtualSelectedParentChainFromBlockRequestMessage{ + string startHash = 1; + bool includeAcceptedTransactionIds = 2; +} + +message AcceptedTransactionIds{ + string acceptingBlockHash = 1; + repeated string acceptedTransactionIds = 2; +} + +message GetVirtualSelectedParentChainFromBlockResponseMessage{ + // The chain blocks that were removed, in high-to-low order + repeated string removedChainBlockHashes = 1; + + // The chain blocks that were added, in low-to-high order + repeated string addedChainBlockHashes = 3; + + // The transactions accepted by each block in addedChainBlockHashes. + // Will be filled only if `includeAcceptedTransactionIds = true` in the request. + repeated AcceptedTransactionIds acceptedTransactionIds = 2; + + RPCError error = 1000; +} + +// GetBlocksRequestMessage requests blocks between a certain block lowHash up to this +// kaspad's current virtual. +message GetBlocksRequestMessage{ + string lowHash = 1; + bool includeBlocks = 2; + bool includeTransactions = 3; +} + +message GetBlocksResponseMessage{ + repeated string blockHashes = 4; + repeated RpcBlock blocks = 3; + RPCError error = 1000; +} + +// GetBlockCountRequestMessage requests the current number of blocks in this kaspad. +// Note that this number may decrease as pruning occurs. +message GetBlockCountRequestMessage{ +} + +message GetBlockCountResponseMessage{ + uint64 blockCount = 1; + uint64 headerCount = 2; + RPCError error = 1000; +} + +// GetBlockDagInfoRequestMessage requests general information about the current state +// of this kaspad's DAG. +message GetBlockDagInfoRequestMessage{ +} + +message GetBlockDagInfoResponseMessage{ + string networkName = 1; + uint64 blockCount = 2; + uint64 headerCount = 3; + repeated string tipHashes = 4; + double difficulty = 5; + int64 pastMedianTime = 6; + repeated string virtualParentHashes = 7; + string pruningPointHash = 8; + uint64 virtualDaaScore = 9; + RPCError error = 1000; +} + +message ResolveFinalityConflictRequestMessage{ + string finalityBlockHash = 1; +} + +message ResolveFinalityConflictResponseMessage{ + RPCError error = 1000; +} + +message NotifyFinalityConflictsRequestMessage{ +} + +message NotifyFinalityConflictsResponseMessage{ + RPCError error = 1000; +} + +message FinalityConflictNotificationMessage{ + string violatingBlockHash = 1; +} + +message FinalityConflictResolvedNotificationMessage{ + string finalityBlockHash = 1; +} + +// ShutDownRequestMessage shuts down this kaspad. +message ShutDownRequestMessage{ +} + +message ShutDownResponseMessage{ + RPCError error = 1000; +} + +// GetHeadersRequestMessage requests headers between the given startHash and the +// current virtual, up to the given limit. +message GetHeadersRequestMessage{ + string startHash = 1; + uint64 limit = 2; + bool isAscending = 3; +} + +message GetHeadersResponseMessage{ + repeated string headers = 1; + RPCError error = 1000; +} + +// NotifyUtxosChangedRequestMessage registers this connection for utxoChanged notifications +// for the given addresses. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: UtxosChangedNotificationMessage +message NotifyUtxosChangedRequestMessage { + repeated string addresses = 1; // Leave empty to get all updates +} + +message NotifyUtxosChangedResponseMessage { + RPCError error = 1000; +} + +// UtxosChangedNotificationMessage is sent whenever the UTXO index had been updated. +// +// See: NotifyUtxosChangedRequestMessage +message UtxosChangedNotificationMessage { + repeated UtxosByAddressesEntry added = 1; + repeated UtxosByAddressesEntry removed = 2; +} + +message UtxosByAddressesEntry { + string address = 1; + RpcOutpoint outpoint = 2; + RpcUtxoEntry utxoEntry = 3; +} + +// StopNotifyingUtxosChangedRequestMessage unregisters this connection for utxoChanged notifications +// for the given addresses. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: UtxosChangedNotificationMessage +message StopNotifyingUtxosChangedRequestMessage { + repeated string addresses = 1; +} + +message StopNotifyingUtxosChangedResponseMessage { + RPCError error = 1000; +} + +// GetUtxosByAddressesRequestMessage requests all current UTXOs for the given kaspad addresses +// +// This call is only available when this kaspad was started with `--utxoindex` +message GetUtxosByAddressesRequestMessage { + repeated string addresses = 1; +} + +message GetUtxosByAddressesResponseMessage { + repeated UtxosByAddressesEntry entries = 1; + + RPCError error = 1000; +} + +// GetBalanceByAddressRequest returns the total balance in unspent transactions towards a given address +// +// This call is only available when this kaspad was started with `--utxoindex` +message GetBalanceByAddressRequestMessage { + string address = 1; +} + +message GetBalanceByAddressResponseMessage { + uint64 balance = 1; + + RPCError error = 1000; +} + +message GetBalancesByAddressesRequestMessage { + repeated string addresses = 1; +} + +message BalancesByAddressEntry{ + string address = 1; + uint64 balance = 2; + + RPCError error = 1000; +} + +message GetBalancesByAddressesResponseMessage { + repeated BalancesByAddressEntry entries = 1; + + RPCError error = 1000; +} + +// GetVirtualSelectedParentBlueScoreRequestMessage requests the blue score of the current selected parent +// of the virtual block. +message GetVirtualSelectedParentBlueScoreRequestMessage { +} + +message GetVirtualSelectedParentBlueScoreResponseMessage { + uint64 blueScore = 1; + + RPCError error = 1000; +} + +// NotifyVirtualSelectedParentBlueScoreChangedRequestMessage registers this connection for +// virtualSelectedParentBlueScoreChanged notifications. +// +// See: VirtualSelectedParentBlueScoreChangedNotificationMessage +message NotifyVirtualSelectedParentBlueScoreChangedRequestMessage { +} + +message NotifyVirtualSelectedParentBlueScoreChangedResponseMessage { + RPCError error = 1000; +} + +// VirtualSelectedParentBlueScoreChangedNotificationMessage is sent whenever the blue score +// of the virtual's selected parent changes. +// +// See NotifyVirtualSelectedParentBlueScoreChangedRequestMessage +message VirtualSelectedParentBlueScoreChangedNotificationMessage { + uint64 virtualSelectedParentBlueScore = 1; +} + +// NotifyVirtualDaaScoreChangedRequestMessage registers this connection for +// virtualDaaScoreChanged notifications. +// +// See: VirtualDaaScoreChangedNotificationMessage +message NotifyVirtualDaaScoreChangedRequestMessage { +} + +message NotifyVirtualDaaScoreChangedResponseMessage { + RPCError error = 1000; +} + +// VirtualDaaScoreChangedNotificationMessage is sent whenever the DAA score +// of the virtual changes. +// +// See NotifyVirtualDaaScoreChangedRequestMessage +message VirtualDaaScoreChangedNotificationMessage { + uint64 virtualDaaScore = 1; +} + +// NotifyPruningPointUTXOSetOverrideRequestMessage registers this connection for +// pruning point UTXO set override notifications. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: NotifyPruningPointUTXOSetOverrideResponseMessage +message NotifyPruningPointUTXOSetOverrideRequestMessage { +} + + +message NotifyPruningPointUTXOSetOverrideResponseMessage { + RPCError error = 1000; +} + +// PruningPointUTXOSetOverrideNotificationMessage is sent whenever the UTXO index +// resets due to pruning point change via IBD. +// +// See NotifyPruningPointUTXOSetOverrideRequestMessage +message PruningPointUTXOSetOverrideNotificationMessage { +} + +// StopNotifyingPruningPointUTXOSetOverrideRequestMessage unregisters this connection for +// pruning point UTXO set override notifications. +// +// This call is only available when this kaspad was started with `--utxoindex` +// +// See: PruningPointUTXOSetOverrideNotificationMessage +message StopNotifyingPruningPointUTXOSetOverrideRequestMessage { +} + +message StopNotifyingPruningPointUTXOSetOverrideResponseMessage { + RPCError error = 1000; +} + +// BanRequestMessage bans the given ip. +message BanRequestMessage{ + string ip = 1; +} + +message BanResponseMessage{ + RPCError error = 1000; +} + +// UnbanRequestMessage unbans the given ip. +message UnbanRequestMessage{ + string ip = 1; +} + +message UnbanResponseMessage{ + RPCError error = 1000; +} + +// GetInfoRequestMessage returns info about the node. +message GetInfoRequestMessage{ +} + +message GetInfoResponseMessage{ + string p2pId = 1; + uint64 mempoolSize = 2; + string serverVersion = 3; + bool isUtxoIndexed = 4; + bool isSynced = 5; + RPCError error = 1000; +} + +message EstimateNetworkHashesPerSecondRequestMessage{ + uint32 windowSize = 1; + string startHash = 2; +} + +message EstimateNetworkHashesPerSecondResponseMessage{ + uint64 networkHashesPerSecond = 1; + RPCError error = 1000; +} + +// NotifyNewBlockTemplateRequestMessage registers this connection for +// NewBlockTemplate notifications. +// +// See: NewBlockTemplateNotificationMessage +message NotifyNewBlockTemplateRequestMessage { +} + +message NotifyNewBlockTemplateResponseMessage { + RPCError error = 1000; +} + +// NewBlockTemplateNotificationMessage is sent whenever a new updated block template is +// available for miners. +// +// See NotifyNewBlockTemplateRequestMessage +message NewBlockTemplateNotificationMessage { +} + +message MempoolEntryByAddress{ + string address = 1; + repeated MempoolEntry sending = 2; + repeated MempoolEntry receiving = 3; +} + +message GetMempoolEntriesByAddressesRequestMessage{ + repeated string addresses = 1; + bool includeOrphanPool = 2; + bool filterTransactionPool = 3; +} + +message GetMempoolEntriesByAddressesResponseMessage{ + repeated MempoolEntryByAddress entries = 1; + + RPCError error = 1000; +} + +message GetCoinSupplyRequestMessage{ +} + +message GetCoinSupplyResponseMessage{ + uint64 maxSompi = 1; // note: this is a hard coded maxSupply, actual maxSupply is expected to deviate by upto -5%, but cannot be measured exactly. + uint64 circulatingSompi = 2; + + RPCError error = 1000; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Nexa/DaemonResponses/GetBlockResponse.cs b/src/Miningcore/Blockchain/Nexa/DaemonResponses/GetBlockResponse.cs new file mode 100644 index 000000000..1aebd4973 --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/DaemonResponses/GetBlockResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Nexa.DaemonResponses; + +public class Block +{ + [JsonProperty("hash")] + public string Hash { get; set; } + + [JsonProperty("txid")] + public string[] Transactions { get; set; } +} diff --git a/src/Miningcore/Blockchain/Nexa/DaemonResponses/GetMiningCandidate.cs b/src/Miningcore/Blockchain/Nexa/DaemonResponses/GetMiningCandidate.cs new file mode 100644 index 000000000..25768ac9a --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/DaemonResponses/GetMiningCandidate.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Nexa.DaemonResponses; + +public class MiningCandidate +{ + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("headerCommitment")] + public string HeaderCommitment { get; set; } + + [JsonProperty("nBits")] + public string NBits { get; set; } +} diff --git a/src/Miningcore/Blockchain/Nexa/DaemonResponses/SubmitMiningSolution.cs b/src/Miningcore/Blockchain/Nexa/DaemonResponses/SubmitMiningSolution.cs new file mode 100644 index 000000000..524520405 --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/DaemonResponses/SubmitMiningSolution.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Nexa.DaemonResponses; + +public class SubmitMiningSolution +{ + /// + /// The height of the block new block. + /// + public long Height { get; set; } + + /// + /// The hash of the new block. + /// + public string Hash { get; set; } + + /// + /// This should be empty if the solution is correct. + /// Otherwise it will contain an error message. + /// + public string Result { get; set; } +} diff --git a/src/Miningcore/Blockchain/Nexa/NexaCommands.cs b/src/Miningcore/Blockchain/Nexa/NexaCommands.cs new file mode 100644 index 000000000..7c82db417 --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/NexaCommands.cs @@ -0,0 +1,8 @@ +namespace Miningcore.Blockchain.Nexa; + + +public static class NexaCommands +{ + public const string GetMiningCandidate = "getminingcandidate"; + public const string SubmitMiningSolution = "submitminingsolution"; +} diff --git a/src/Miningcore/Blockchain/Nexa/NexaJob.cs b/src/Miningcore/Blockchain/Nexa/NexaJob.cs new file mode 100644 index 000000000..a0beeba69 --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/NexaJob.cs @@ -0,0 +1,178 @@ +using System.Collections.Concurrent; +using System.Globalization; +using System.Text; +using Miningcore.Blockchain.Bitcoin.DaemonResponses; +using Miningcore.Blockchain.Nexa.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Crypto; +using Miningcore.Extensions; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using Miningcore.Blockchain.Bitcoin; +using NBitcoin; +using Contract = Miningcore.Contracts.Contract; + +namespace Miningcore.Blockchain.Nexa; + +public class NexaJob +{ + private IMasterClock clock; + private IHashAlgorithm headerHasher; + private double shareMultiplier; + private BitcoinTemplate coin; + private readonly ConcurrentDictionary submissions = new(StringComparer.OrdinalIgnoreCase); + private uint256 blockTargetValue; + private object[] jobParams; + + private BlockTemplate BlockTemplate { get; set; } + public MiningCandidate MiningCandidate { get; private set; } + private byte[] headerCommitmentRev; + public double Difficulty { get; private set; } + public string JobId { get; private set; } + + protected virtual (Share Share, object submitParams) ProcessShareInternal( + StratumConnection worker, string nonce, string extraNonce1) + { + var context = worker.ContextAs(); + var extraNonce1Bytes = extraNonce1.HexToByteArray(); + var nonceBytes = nonce.HexToByteArray(); + + Span nonceFinal = stackalloc byte[12]; // 4 bytes extra nonce + 8 bytes nonce + using(var stream = new MemoryStream()) + { + stream.Write(extraNonce1Bytes); + stream.Write(nonceBytes); + + nonceFinal = stream.ToArray(); + } + + Span miningHashBytes = stackalloc byte[44]; // 32 bytes commitment + 4 bytes extra nonce + 8 bytes nonce + using(var stream = new MemoryStream()) + { + stream.Write(headerCommitmentRev); + stream.Write(new byte[] {0x0c}); // nonceFinal.Length + stream.Write(nonceFinal); + + miningHashBytes = stream.ToArray(); + } + + Span powHash = stackalloc byte[32]; + headerHasher.Digest(miningHashBytes, powHash); + var miningValue = new uint256(powHash); + + var shareDiff = (double) new BigRational(BitcoinConstants.Diff1, powHash.ToBigInteger()) * shareMultiplier; + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = miningValue <= 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 submitParams = new object[] + { + new + { + id = this.MiningCandidate.Id, + nonce = nonceFinal.ToHexString() + } + }; + + var share = new Share + { + BlockHeight = BlockTemplate.Height, + NetworkDifficulty = Difficulty, + Difficulty = stratumDifficulty / shareMultiplier, + IsBlockCandidate = isBlockCandidate, + }; + + return (share, submitParams); + } + + public void Init(MiningCandidate miningCandidate, BlockTemplate blockTemplate, + string jobId, PoolConfig pc, IMasterClock clock, double shareMultiplier, IHashAlgorithm headerHasher) + { + Contract.RequiresNonNull(miningCandidate); + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(pc); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(headerHasher); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + + coin = pc.Template.As(); + MiningCandidate = miningCandidate; + BlockTemplate = blockTemplate; + this.shareMultiplier = shareMultiplier; + JobId = jobId; + this.headerHasher = headerHasher; + this.clock = clock; + Difficulty = new Target(System.Numerics.BigInteger.Parse(BlockTemplate.Target, NumberStyles.HexNumber)).Difficulty; + headerCommitmentRev = miningCandidate.HeaderCommitment.HexToReverseByteArray(); + + if(!string.IsNullOrEmpty(BlockTemplate.Target)) + blockTargetValue = new uint256(BlockTemplate.Target); + else + { + var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); + blockTargetValue = tmp.ToUInt256(); + } + + jobParams = new object[] + { + JobId, + headerCommitmentRev.ToHexString(), + blockTemplate.Height, + miningCandidate.NBits, + }; + } + + public object GetJobParams() + { + return jobParams; + } + + private bool RegisterSubmit(string headerCommitment, string extraNonce1, string nonce) + { + var key = new StringBuilder() + .Append(headerCommitment) + .Append(extraNonce1) + .Append(nonce) + .ToString(); + + return submissions.TryAdd(key, true); + } + + public (Share Share, object param) ProcessShare(StratumConnection worker, string nonce, string extraNonce1) + { + Contract.Requires(!string.IsNullOrEmpty(nonce)); + Contract.Requires(!string.IsNullOrEmpty(extraNonce1)); + + // validate nonce. must be 8 bytes (16 hex chars without prefix) + if(nonce.Length != 16) + throw new StratumException(StratumError.Other, "incorrect size of nonce"); + + // dupe check + if(!RegisterSubmit(this.MiningCandidate.HeaderCommitment, extraNonce1, nonce)) + throw new StratumException(StratumError.DuplicateShare, "duplicate share"); + + return ProcessShareInternal(worker, nonce, extraNonce1); + } +} diff --git a/src/Miningcore/Blockchain/Nexa/NexaJobManager.cs b/src/Miningcore/Blockchain/Nexa/NexaJobManager.cs new file mode 100644 index 000000000..b18926a9c --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/NexaJobManager.cs @@ -0,0 +1,349 @@ +using System.Globalization; +using Autofac; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Bitcoin.Configuration; +using Miningcore.Blockchain.Nexa.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Contracts; +using Miningcore.Crypto; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Notifications.Messages; +using Miningcore.Rpc; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using NLog; +using BlockTemplate = Miningcore.Blockchain.Bitcoin.DaemonResponses.BlockTemplate; + +namespace Miningcore.Blockchain.Nexa; + +public class NexaJobManager : BitcoinJobManagerBase +{ + public NexaJobManager( + IComponentContext ctx, + IMasterClock clock, + IMessageBus messageBus, + IExtraNonceProvider extraNonceProvider) : + base(ctx, clock, messageBus, extraNonceProvider) + { + } + + private BitcoinTemplate coin; + private string poolAddress; + private BlockTemplate blockTemplate; + + + private object[] GetMiningCandidateParams() + { + return new object[] + { + null, + poolAddress, + }; + } + + private async Task> GetMiningCandidateAsync(CancellationToken ct) + { + var result = await rpc.ExecuteAsync(logger, + NexaCommands.GetMiningCandidate, ct, GetMiningCandidateParams()); + + return result; + } + + private static RpcResponse GetMiningCandidateFromJson(string json) + { + var result = JsonConvert.DeserializeObject>(json); + + return result; + } + + private async Task> GetBlockTemplateAsync(CancellationToken ct) + { + var result = await rpc.ExecuteAsync(logger, + BitcoinCommands.GetBlockTemplate, ct, extraPoolConfig?.GBTArgs ?? (object) GetBlockTemplateParams()); + + return result; + } + + private static NexaJob CreateJob() + { + return new NexaJob(); + } + + protected override void PostChainIdentifyConfigure() + { + base.PostChainIdentifyConfigure(); + + if(poolConfig.EnableInternalStratum == true && coin.HeaderHasherValue is IHashAlgorithmInit hashInit) + { + if(!hashInit.DigestInit(poolConfig)) + logger.Error(() => $"{hashInit.GetType().Name} initialization failed"); + } + } + + protected override async Task<(bool IsNew, bool Force)> UpdateJob(CancellationToken ct, bool forceUpdate, string via = null, string json = null) + { + try + { + if(forceUpdate) + lastJobRebroadcast = clock.Now; + + var response = string.IsNullOrEmpty(json) ? + await GetMiningCandidateAsync(ct) : + GetMiningCandidateFromJson(json); + + // may happen if daemon is currently not connected to peers + if(response.Error != null) + { + logger.Warn(() => $"Unable to update job. GetMiningCandidate failed. Daemon responded with: {response.Error.Message} Code {response.Error.Code}"); + return (false, forceUpdate); + } + + var miningCandidate = response.Response; + var job = currentJob; + + var isNew = job == null || + (miningCandidate != null && + (job.MiningCandidate.HeaderCommitment != miningCandidate.HeaderCommitment || + miningCandidate.Id > job.MiningCandidate?.Id)); + + if(isNew) + { + var gbtResponse = await GetBlockTemplateAsync(ct); + if(gbtResponse.Error != null) + { + logger.Warn(() => $"Unable to update job. GetBlockTemplate failed. Daemon responded with: {gbtResponse.Error.Message} Code {gbtResponse.Error.Code}"); + return (false, forceUpdate); + } + blockTemplate = gbtResponse.Response; + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); + } + + if(isNew || forceUpdate) + { + job = CreateJob(); + + 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) + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Height}"); + + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = blockTemplate.Height; + BlockchainStats.NetworkDifficulty = job.Difficulty; + BlockchainStats.NextNetworkTarget = blockTemplate.Target; + BlockchainStats.NextNetworkBits = blockTemplate.Bits; + } + + else + { + if(via != null) + logger.Debug(() => $"Template update {blockTemplate?.Height} [{via}]"); + else + logger.Debug(() => $"Template update {blockTemplate?.Height}"); + } + + currentJob = job; + } + + return (isNew, forceUpdate); + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); + } + + return (false, forceUpdate); + } + + protected override object GetJobParamsForStratum(bool isNew) + { + var job = currentJob; + return job?.GetJobParams(); + } + + #region API-Surface + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + poolAddress = pc.Address; + coin = pc.Template.As(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + + if(extraPoolConfig?.MaxActiveJobs.HasValue == true) + maxActiveJobs = extraPoolConfig.MaxActiveJobs.Value; + + 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, + BitcoinConstants.ExtranoncePlaceHolderLength - ExtranonceBytes, + }; + + return responseData; + } + + public 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(); + + var workerValue = (submitParams[0] as string)?.Trim(); + var jobId = submitParams[1] as string; + var extraNonce1 = submitParams[2] as string; + //var nTime = submitParams[3] as string; // not really required + var nonce = submitParams[4] as string; + + if(string.IsNullOrEmpty(workerValue)) + throw new StratumException(StratumError.Other, "missing or invalid workername"); + + if(extraNonce1 != context.ExtraNonce1) + throw new StratumException(StratumError.Other, "invalid extranonce"); + + NexaJob job; + + lock(jobLock) + { + job = validJobs.FirstOrDefault(x => x.JobId == jobId); + } + + if(job == null) + throw new StratumException(StratumError.JobNotFound, "job not found"); + + // validate & process + var (share, args) = job.ProcessShare(worker, nonce, extraNonce1); + + // 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}"); + + var acceptResponse = await SubmitBlockAsync(share, args, ct); + + // is it still a block candidate? + share.IsBlockCandidate = acceptResponse.Accepted; + share.BlockHash = acceptResponse.BlockHash; + + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash}] submitted by {context.Miner}"); + + OnBlockFound(); + + // persist the coinbase transaction-hash to allow the payment processor + // to verify later on that the pool has received the reward for the block + share.TransactionConfirmationData = acceptResponse.CoinbaseTx; + } + + else + { + // clear fields that no longer apply + share.TransactionConfirmationData = null; + } + } + + return share; + } + + public double ShareMultiplier => coin.ShareMultiplier; + + protected new record SubmitResult(bool Accepted, string BlockHash, string CoinbaseTx); + + protected async Task SubmitBlockAsync(Share share, object args, CancellationToken ct) + { + var rawSubmitRes = await rpc.ExecuteAsync(logger, NexaCommands.SubmitMiningSolution, ct, payload: args); + + // TODO: maybe refactor this. Try to deserialize first and if there is an error, treat the response as a string + + var rawSubmitString = rawSubmitRes?.Response.ToString(); + string submitError = null; + SubmitMiningSolution submitResult = null; + if(string.IsNullOrEmpty(rawSubmitString) || rawSubmitRes.Error != null || rawSubmitString == "id not found (stale candidate)") + { + submitError = rawSubmitRes?.Error?.Message ?? + rawSubmitRes?.Error?.Code.ToString(CultureInfo.InvariantCulture) ?? + rawSubmitString ?? + "unknown error"; + } + else + { + submitResult = JsonConvert.DeserializeObject(rawSubmitString); + if(!string.IsNullOrEmpty(submitResult.Result)) + { + submitError = submitResult.Result; + } + } + + if(!string.IsNullOrEmpty(submitError)) + { + logger.Warn(() => $"Block {share.BlockHeight} submission failed with: {submitError}"); + messageBus.SendMessage(new AdminNotification("Block submission failed", $"Pool {poolConfig.Id} {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}failed to submit block {share.BlockHeight}: {submitError}")); + return new SubmitResult(false, null, null); + } + + + var blockResult = await rpc.ExecuteAsync(logger, BitcoinCommands.GetBlock, ct, new object[] { submitResult?.Hash }); + var block = blockResult?.Response; + + var accepted = blockResult != null && blockResult.Error == null; + + if(!accepted) + { + logger.Warn(() => $"Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission"); + messageBus.SendMessage(new AdminNotification($"[{share.PoolId.ToUpper()}]-[{share.Source}] Block submission failed", $"[{share.PoolId.ToUpper()}]-[{share.Source}] Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission")); + } + + return new SubmitResult(accepted, block?.Hash, block?.Transactions.FirstOrDefault()); + } + + #endregion // API-Surface +} diff --git a/src/Miningcore/Blockchain/Nexa/NexaPool.cs b/src/Miningcore/Blockchain/Nexa/NexaPool.cs new file mode 100644 index 000000000..160a8b604 --- /dev/null +++ b/src/Miningcore/Blockchain/Nexa/NexaPool.cs @@ -0,0 +1,389 @@ +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using Autofac; +using AutoMapper; +using Microsoft.IO; +using Miningcore.Configuration; +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; +using Miningcore.Blockchain.Bitcoin; + +namespace Miningcore.Blockchain.Nexa; + +[CoinFamily(CoinFamily.Nexa)] +public class NexaPool : PoolBase +{ + public NexaPool(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 NexaJobManager manager; + private BitcoinTemplate 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(); + + var data = new object[] + { + new object[] + { + new object[] { BitcoinStratumMethods.SetDifficulty, connection.ConnectionId }, + new object[] { BitcoinStratumMethods.MiningNotify, connection.ConnectionId } + } + } + .Concat(manager.GetSubscriberData(connection)) + .ToArray(); + + await connection.RespondAsync(data, request.Id); + + // setup worker context + context.IsSubscribed = true; + context.UserAgent = requestParams.FirstOrDefault()?.Trim(); + + // 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); + } + + // send intial update + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + } + + 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(); + var requestParams = request.ParamsAs(); + 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) + { + // respond + await connection.RespondAsync(context.IsAuthorized, request.Id); + + // 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}"); + + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + } + } + + 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); + } + } + } + + 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); + await connection.RespondAsync(true, request.Id); + + // 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; + } + } + + private async Task OnSuggestDifficultyAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + // acknowledge + await connection.RespondAsync(true, request.Id); + + try + { + var requestedDiff = (double) Convert.ChangeType(request.Params, TypeCode.Double)!; + + // client may suggest higher-than-base difficulty, but not a lower one + var poolEndpoint = poolConfig.Ports[connection.LocalEndpoint.Port]; + + if(requestedDiff > poolEndpoint.Difficulty) + { + context.SetDifficulty(requestedDiff); + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { context.Difficulty }); + + logger.Info(() => $"[{connection.ConnectionId}] Difficulty set to {requestedDiff} as requested by miner"); + } + } + + catch(Exception ex) + { + logger.Error(ex, () => $"Unable to convert suggested difficulty {request.Params}"); + } + } + + 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(); + + // 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); + })); + } + + public override double HashrateFromShares(double shares, double interval) + { + var multiplier = BitcoinConstants.Pow2x32; + var result = shares * multiplier / interval; + + if(coin.HashrateMultiplier.HasValue) + result *= coin.HashrateMultiplier.Value; + + return result; + } + + public override double ShareMultiplier => coin.ShareMultiplier; + + #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( + new TypedParameter(typeof(IExtraNonceProvider), new BitcoinExtraNonceProvider(poolConfig.Id, 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 BitcoinWorkerContext(); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + + try + { + switch(request.Method) + { + case BitcoinStratumMethods.Subscribe: + await OnSubscribeAsync(connection, tsRequest); + break; + + case BitcoinStratumMethods.Authorize: + await OnAuthorizeAsync(connection, tsRequest, ct); + break; + + case BitcoinStratumMethods.SubmitShare: + await OnSubmitAsync(connection, tsRequest, ct); + break; + + case BitcoinStratumMethods.SuggestDifficulty: + await OnSuggestDifficultyAsync(connection, tsRequest); + break; + + case BitcoinStratumMethods.ExtraNonceSubscribe: + await connection.RespondAsync(true, request.Id); + 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()) + { + await connection.NotifyAsync(BitcoinStratumMethods.SetDifficulty, new object[] { connection.Context.Difficulty }); + await connection.NotifyAsync(BitcoinStratumMethods.MiningNotify, currentJobParams); + } + } + + #endregion // Overrides +} diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index b72e5ead3..e0fd5e189 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -39,7 +39,13 @@ public enum CoinFamily [EnumMember(Value = "ethereum")] Ethereum, - + + [EnumMember(Value = "kaspa")] + Kaspa, + + [EnumMember(Value = "nexa")] + Nexa, + [EnumMember(Value = "progpow")] Progpow, } @@ -147,6 +153,8 @@ public abstract partial class CoinTemplate {CoinFamily.Equihash, typeof(EquihashCoinTemplate)}, {CoinFamily.Ergo, typeof(ErgoCoinTemplate)}, {CoinFamily.Ethereum, typeof(EthereumCoinTemplate)}, + {CoinFamily.Kaspa, typeof(KaspaCoinTemplate)}, + {CoinFamily.Nexa, typeof(BitcoinTemplate)}, {CoinFamily.Progpow, typeof(ProgpowCoinTemplate)}, }; } @@ -245,6 +253,18 @@ public class BitcoinNetworkParams [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string BlockSerializer { get; set; } + + /// + /// Force the use of the raw public key of the specified poolAddress + /// + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public bool ForcePoolAddressDestinationWithPubKey { get; set; } + + /// + /// Amount of decimals used for payouts + /// + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? PayoutDecimalPlaces { get; set; } = 4; } public enum ConcealSubfamily @@ -268,11 +288,17 @@ public partial class ConcealCoinTemplate : CoinTemplate public CryptonightHashType Hash { get; set; } /// - /// Set to 0 for automatic selection from blobtemplate + /// 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/CryptoNoteConfig.h @@ -415,10 +441,16 @@ public partial class CryptonoteCoinTemplate : CoinTemplate public CryptonightHashType Hash { get; set; } /// - /// Set to 0 for automatic selection from blobtemplate + /// 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; } /// /// Smallest unit for Blockreward formatting @@ -615,6 +647,10 @@ public partial class EthereumCoinTemplate : CoinTemplate public string Ethasher { get; set; } = "ethash"; } +public partial class KaspaCoinTemplate : CoinTemplate +{ +} + public partial class ProgpowCoinTemplate : BitcoinTemplate { /// diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index 9505385e5..247132011 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -214,6 +214,18 @@ public override string GetAlgorithmName() #endregion } +public partial class ErgoCoinTemplate +{ + #region Overrides of CoinTemplate + + public override string GetAlgorithmName() + { + return "Autolykos"; + } + + #endregion +} + public partial class EthereumCoinTemplate { #region Overrides of CoinTemplate @@ -238,13 +250,22 @@ public override string GetAlgorithmName() #endregion } -public partial class ErgoCoinTemplate +public partial class KaspaCoinTemplate { #region Overrides of CoinTemplate public override string GetAlgorithmName() { - return "Autolykos"; + switch(Symbol) + { + case "KLS": + return "Karlsenhash"; + case "PYI": + return "Pyrinhash"; + default: + // TODO: return variant + return "kHeavyHash"; + } } #endregion diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Blake2b.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Blake2b.cs index a08fff4fb..240f52ce2 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Blake2b.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Blake2b.cs @@ -6,6 +6,13 @@ namespace Miningcore.Crypto.Hashing.Algorithms; [Identifier("blake2b")] public unsafe class Blake2b : IHashAlgorithm { + public byte[] dataKey { get; protected set; } = null; + + public Blake2b(byte[] dataKey = null) + { + this.dataKey = dataKey; + } + public void Digest(ReadOnlySpan data, Span result, params object[] extra) { Contract.Requires(result.Length >= 32); @@ -14,7 +21,11 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e { fixed (byte* output = result) { - Multihash.blake2b(input, output, (uint) data.Length, result.Length); + fixed (byte* key = this.dataKey) + { + var keyLength = (this.dataKey == null) ? 0 : this.dataKey.Length; + Multihash.blake2b(input, output, (uint) data.Length, result.Length, key, (uint) keyLength); + } } } } diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs index 8c006e5a2..e8c160cf1 100644 --- a/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Blake3.cs @@ -6,6 +6,13 @@ namespace Miningcore.Crypto.Hashing.Algorithms; [Identifier("blake3")] public unsafe class Blake3 : IHashAlgorithm { + public byte[] dataKey { get; protected set; } = null; + + public Blake3(byte[] dataKey = null) + { + this.dataKey = dataKey; + } + public void Digest(ReadOnlySpan data, Span result, params object[] extra) { Contract.Requires(result.Length >= 32); @@ -14,7 +21,11 @@ public void Digest(ReadOnlySpan data, Span result, params object[] e { fixed (byte* output = result) { - Multihash.blake3(input, output, (uint) data.Length); + fixed (byte* key = this.dataKey) + { + var keyLength = (this.dataKey == null) ? 0 : this.dataKey.Length; + Multihash.blake3(input, output, (uint) data.Length, key, (uint) keyLength); + } } } } diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/CShake128.cs b/src/Miningcore/Crypto/Hashing/Algorithms/CShake128.cs new file mode 100644 index 000000000..bdbee7863 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/CShake128.cs @@ -0,0 +1,39 @@ +using System.Security.Cryptography; +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("cshake128")] +public unsafe class CShake128 : IHashAlgorithm +{ + public byte[] dataName { get; protected set; } = null; + public byte[] dataCustom { get; protected set; } = null; + + public CShake128(byte[] dataName = null, byte[] dataCustom = null) + { + this.dataName = dataName; + this.dataCustom = dataCustom; + } + + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + fixed (byte* name = this.dataName) + { + var nameLength = (this.dataName == null) ? 0 : this.dataName.Length; + fixed (byte* custom = this.dataCustom) + { + var customLength = (this.dataCustom == null) ? 0 : this.dataCustom.Length; + Multihash.cshake128(input, (uint) data.Length, name, (uint) nameLength, custom, (uint) customLength, output, (uint) result.Length); + } + } + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/CShake256.cs b/src/Miningcore/Crypto/Hashing/Algorithms/CShake256.cs new file mode 100644 index 000000000..b679538c7 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/CShake256.cs @@ -0,0 +1,39 @@ +using System.Security.Cryptography; +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("cshake256")] +public unsafe class CShake256 : IHashAlgorithm +{ + public byte[] dataName { get; protected set; } = null; + public byte[] dataCustom { get; protected set; } = null; + + public CShake256(byte[] dataName = null, byte[] dataCustom = null) + { + this.dataName = dataName; + this.dataCustom = dataCustom; + } + + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + fixed (byte* name = this.dataName) + { + var nameLength = (this.dataName == null) ? 0 : this.dataName.Length; + fixed (byte* custom = this.dataCustom) + { + var customLength = (this.dataCustom == null) ? 0 : this.dataCustom.Length; + Multihash.cshake256(input, (uint) data.Length, name, (uint) nameLength, custom, (uint) customLength, output, (uint) result.Length); + } + } + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/NexaPow.cs b/src/Miningcore/Crypto/Hashing/Algorithms/NexaPow.cs new file mode 100644 index 000000000..346e6a84f --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/NexaPow.cs @@ -0,0 +1,84 @@ +using System.Diagnostics; +using System.Security.Cryptography; +using Miningcore.Configuration; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Notifications.Messages; +using NLog; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +/// +/// NexaPow +/// +[Identifier("nexapow")] +public unsafe class NexaPow : + IHashAlgorithm, + IHashAlgorithmInit +{ + private IntPtr ctx = IntPtr.Zero; + internal static IMessageBus messageBus; + + public void Digest(ReadOnlySpan data, Span result, params object[] extra) + { + Contract.Requires(result.Length >= 32); + Contract.RequiresNonNull(ctx); + + var sw = Stopwatch.StartNew(); + int success; + + // Calculate miningHash which is the double_sha256(candidateHash || nonce) + Span miningHash = stackalloc byte[32]; + var dsha = new Sha256D(); + dsha.Digest(data, miningHash); + + // Calculate h1, the sha256(miningHash) + Span h1 = stackalloc byte[32]; + using(var hasher = SHA256.Create()) + { + hasher.TryComputeHash(miningHash, h1, out _); + } + + Span signature = stackalloc byte[64]; + fixed(byte* input = h1) + { + fixed(byte* output = signature) + { + // Use miningHash as a private key (POW fails if it is invalid) + fixed(byte* key = miningHash) + { + // Sign h1 resulting in sig + success = Native.NexaPow.schnorr_sign(ctx, input, output, key, (uint) h1.Length); + } + } + } + + // powhash = sha256(sig) + using(var hasher = SHA256.Create()) + { + hasher.TryComputeHash(signature, result, out _); + } + + if(success == 0) + { + Logger.Error(() => "Failed to sign hash"); + } + + messageBus?.SendTelemetry("NexaPow", TelemetryCategory.Hash, sw.Elapsed, success == 1); + } + + private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + + public bool DigestInit(PoolConfig poolConfig) + { + ctx = Native.NexaPow.schnorr_init(); + if(ctx == IntPtr.Zero) + { + Logger.Error(() => "Failed to initialize schnorr context"); + return false; + } + Logger.Info(() => "Initialized schnorr context"); + return true; + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Shake128.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Shake128.cs new file mode 100644 index 000000000..ded7d767f --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Shake128.cs @@ -0,0 +1,22 @@ +using System.Security.Cryptography; +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("shake128")] +public unsafe class Shake128 : 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.shake128(input, (uint) data.Length, output, (uint) result.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Algorithms/Shake256.cs b/src/Miningcore/Crypto/Hashing/Algorithms/Shake256.cs new file mode 100644 index 000000000..29607c63b --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Algorithms/Shake256.cs @@ -0,0 +1,22 @@ +using System.Security.Cryptography; +using Miningcore.Contracts; +using Miningcore.Native; + +namespace Miningcore.Crypto.Hashing.Algorithms; + +[Identifier("shake256")] +public unsafe class Shake256 : 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.shake256(input, (uint) data.Length, output, (uint) result.Length); + } + } + } +} diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs index 7b3567b6f..fb0383d12 100644 --- a/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Cache.cs @@ -84,13 +84,13 @@ await Task.Run(() => return; var started = DateTime.Now; - var block = Epoch * RethereumConstants.EpochLength; + var block = Epoch * HypraConstants.EpochLength; // Full DAG if(!string.IsNullOrEmpty(dagDir)) { logger.Debug(() => $"Generating DAG for epoch {Epoch}"); - logger.Debug(() => $"Epoch length used: {RethereumConstants.EpochLength}"); + logger.Debug(() => $"Epoch length used: {HypraConstants.EpochLength}"); // Generate a temporary cache var light = EthHashB3.ethash_light_new(block); diff --git a/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs index 650628ef0..5887f1726 100644 --- a/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs +++ b/src/Miningcore/Crypto/Hashing/Ethash/Ethashb3/Ethashb3Light.cs @@ -30,7 +30,7 @@ public void Dispose() public async Task GetCacheAsync(ILogger logger, ulong block, CancellationToken ct) { - var epoch = block / RethereumConstants.EpochLength; + var epoch = block / HypraConstants.EpochLength; Cache result; lock(cacheLock) diff --git a/src/Miningcore/Miningcore.csproj b/src/Miningcore/Miningcore.csproj index 2878d8e5d..60752cbe0 100644 --- a/src/Miningcore/Miningcore.csproj +++ b/src/Miningcore/Miningcore.csproj @@ -49,18 +49,18 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -78,11 +78,18 @@ - - + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/src/Miningcore/Native/Cryptonote.cs b/src/Miningcore/Native/Cryptonote.cs index e3767c467..7e904d61d 100644 --- a/src/Miningcore/Native/Cryptonote.cs +++ b/src/Miningcore/Native/Cryptonote.cs @@ -8,7 +8,10 @@ namespace Miningcore.Native; public static unsafe class CryptonoteBindings { [DllImport("libcryptonote", EntryPoint = "convert_blob_export", CallingConvention = CallingConvention.Cdecl)] - private static extern bool convert_blob(byte* input, int inputSize, byte* output, ref int outputSize); + private static extern bool convert_blob(byte* input, int inputSize, byte* output, ref int outputSize, int blobType); + + [DllImport("libcryptonote", EntryPoint = "get_block_id_export", CallingConvention = CallingConvention.Cdecl)] + private static extern bool get_block_id(byte* input, int inputSize, byte* output, int blobType); [DllImport("libcryptonote", EntryPoint = "decode_address_export", CallingConvention = CallingConvention.Cdecl)] private static extern ulong decode_address(byte* input, int inputSize); @@ -19,7 +22,7 @@ public static unsafe class CryptonoteBindings [DllImport("libcryptonote", EntryPoint = "cn_fast_hash_export", CallingConvention = CallingConvention.Cdecl)] private static extern int cn_fast_hash(byte* input, byte* output, uint inputLength); - public static byte[] ConvertBlob(ReadOnlySpan data, int size) + public static byte[] ConvertBlob(ReadOnlySpan data, int size, int blobType = 0) { Contract.Requires(data.Length > 0); @@ -35,7 +38,7 @@ public static byte[] ConvertBlob(ReadOnlySpan data, int size) var success = false; fixed (byte* output = outputBuffer) { - success = convert_blob(input, size, output, ref outputBufferLength); + success = convert_blob(input, size, output, ref outputBufferLength, blobType); } if(!success) @@ -50,7 +53,7 @@ public static byte[] ConvertBlob(ReadOnlySpan data, int size) fixed (byte* output = outputBuffer) { - success = convert_blob(input, size, output, ref outputBufferLength); + success = convert_blob(input, size, output, ref outputBufferLength, blobType); } if(!success) @@ -70,6 +73,19 @@ public static byte[] ConvertBlob(ReadOnlySpan data, int size) } } } + + public static void GetBlockId(ReadOnlySpan data, Span result, int blobType = 0) + { + Contract.Requires(result.Length >= 32); + + fixed (byte* input = data) + { + fixed (byte* output = result) + { + get_block_id(input, data.Length, output, blobType); + } + } + } public static ulong DecodeAddress(string address) { diff --git a/src/Miningcore/Native/Multihash.cs b/src/Miningcore/Native/Multihash.cs index f3799c463..83aa3c589 100644 --- a/src/Miningcore/Native/Multihash.cs +++ b/src/Miningcore/Native/Multihash.cs @@ -18,6 +18,18 @@ 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); + + [DllImport("libmultihash", EntryPoint = "shake256_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void shake256(byte* input, uint inputLength, void* output, uint outputLength); [DllImport("libmultihash", EntryPoint = "hmq17_export", CallingConvention = CallingConvention.Cdecl)] public static extern void hmq17(byte* input, void* output, uint inputLength); @@ -83,10 +95,10 @@ public static unsafe class Multihash public static extern void blake2s(byte* input, void* output, uint inputLength, int outputLength = -1); [DllImport("libmultihash", EntryPoint = "blake2b_export", CallingConvention = CallingConvention.Cdecl)] - public static extern void blake2b(byte* input, void* output, uint inputLength, int outputLength); + 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); + public static extern void blake3(byte* input, void* output, uint inputLength, byte* key, uint keyLength); [DllImport("libmultihash", EntryPoint = "dcrypt_export", CallingConvention = CallingConvention.Cdecl)] public static extern void dcrypt(byte* input, void* output, uint inputLength); diff --git a/src/Miningcore/Native/NexaPow.cs b/src/Miningcore/Native/NexaPow.cs new file mode 100644 index 000000000..98b8dc2b4 --- /dev/null +++ b/src/Miningcore/Native/NexaPow.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Miningcore.Native; + +public static unsafe class NexaPow +{ + [DllImport("libnexapow", EntryPoint = "schnorr_init_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr schnorr_init(); + + [DllImport("libnexapow", EntryPoint = "schnorr_sign_export", CallingConvention = CallingConvention.Cdecl)] + public static extern int schnorr_sign(IntPtr ctx, byte* input, void* output, byte* key, uint inputLength); +} diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs index e5c53efb2..837438c9e 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs @@ -76,6 +76,24 @@ public async Task PageBlocksAsync(IDbConnection con, BlockStatus[] stat .ToArray(); } + 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 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 + }, cancellationToken: ct))) + .Select(mapper.Map) + .ToArray(); + } + public async Task GetPendingBlocksForPoolAsync(IDbConnection con, string poolId) { const string query = @"SELECT * FROM blocks WHERE poolid = @poolid AND status = @status"; @@ -118,6 +136,13 @@ public Task GetPoolBlockCountAsync(IDbConnection con, string poolId, Cance 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"; + + return con.ExecuteScalarAsync(new CommandDefinition(query, new { poolId, address }, cancellationToken: ct)); + } public Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId) { diff --git a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs index 26b355d9f..cdd80e863 100644 --- a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs @@ -11,10 +11,12 @@ public interface IBlockRepository Task PageBlocksAsync(IDbConnection con, string poolId, BlockStatus[] status, int page, int pageSize, CancellationToken ct); Task PageBlocksAsync(IDbConnection con, BlockStatus[] status, int page, int pageSize, CancellationToken ct); + 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 GetBlockBeforeCountAsync(IDbConnection con, string poolId, BlockStatus[] status, DateTime before); Task GetPoolBlockCountAsync(IDbConnection con, string poolId, CancellationToken ct); + Task GetMinerBlockCountAsync(IDbConnection con, string poolId, string address, CancellationToken ct); Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId); Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, string poolId, long height, string type); Task GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status); diff --git a/src/Miningcore/Program.cs b/src/Miningcore/Program.cs index e13011bc7..102d09a5e 100644 --- a/src/Miningcore/Program.cs +++ b/src/Miningcore/Program.cs @@ -29,7 +29,10 @@ using Miningcore.Crypto.Hashing.Equihash; using Miningcore.Crypto.Hashing.Ethash.Etchash; using Miningcore.Crypto.Hashing.Ethash.Ethash; +using Miningcore.Crypto.Hashing.Ethash.Ethashb3; using Miningcore.Crypto.Hashing.Ethash.Ubqhash; +using Miningcore.Crypto.Hashing.Progpow.Firopow; +using Miningcore.Crypto.Hashing.Progpow.Kawpow; using Miningcore.Extensions; using Miningcore.Messaging; using Miningcore.Mining; @@ -623,16 +626,17 @@ private static void Logo() ██║╚██╔╝██║██║██║╚██╗██║██║██║╚██╗██║██║ ██║██║ ██║ ██║██╔══██╗██╔══╝ ██║ ╚═╝ ██║██║██║ ╚████║██║██║ ╚████║╚██████╔╝╚██████╗╚██████╔╝██║ ██║███████╗ "); - Console.WriteLine(" https://github.com/oliverw/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 - miningcore.eth (ENS Address)"); - Console.WriteLine(" BTC - miningcore.eth (ENS Address)"); - Console.WriteLine(" LTC - miningcore.eth (ENS Address)"); - Console.WriteLine(" DASH - XqpBAV9QCaoLnz42uF5frSSfrJTrqHoxjp"); - Console.WriteLine(" ZEC - t1YHZHz2DGVMJiggD2P4fBQ2TAPgtLSUwZ7"); - Console.WriteLine(" ZCL - t1MFU1vD3YKgsK6Uh8hW7UTY8mKAV2xVqBr"); - Console.WriteLine(" ETC - 0xF8cCE9CE143C68d3d4A7e6bf47006f21Cfcf93c0"); - Console.WriteLine(" XMR - 475YVJbPHPedudkhrcNp1wDcLMTGYusGPF5fqE7XjnragVLPdqbCHBdZg3dF4dN9hXMjjvGbykS6a77dTAQvGrpiQqHp2eH"); + Console.WriteLine(" ETH - 0xbC059e88A4dD11c2E882Fc6B83F8Ec12E4CCCFad"); + Console.WriteLine(" BTC - 16xvkGfG9nrJSKKo5nGWphP8w4hr2ZzVuw"); + Console.WriteLine(" LTC - LLs76baYT7iMqQhizxtBC96Cy48iX3Eh1p"); + Console.WriteLine(" DOGE - DFuvDSFh4N3SiXGDnye2Vbc8kqvMHbyQE1"); + Console.WriteLine(" KAS - kaspa:qpmf0wyu7c5z4l82ax9cfc5ughwk2f9lgu8uckkqrrpjqkxuk7yrga5nntvgn"); + Console.WriteLine(" CCX - ccx7S4B3gBeH1SGWCfqZp3NM7Vavg7H3S8ovJn8fU4bwC4vU7ChWfHtbNzifhrpbJ74bMDxj4KZFTcznTfsucCEg1Kgv7zbNgs"); + Console.WriteLine(" FIRO - a5AsoTSkfPHQ3SUmR6binG1XW7oQQoFNU1"); + Console.WriteLine(" ERGO - 9gYyuZzaSw3TiCtUkSRuS3XVDUv41EFs3dtNCFGqiEwHqpb7gkF"); + Console.WriteLine(" XMR - 483zaHtMRfM7rw1dXgebhWaRR8QLgAF6w4BomAV319FVVHfdbYTLVuBRc4pQgRAnRpfy6CXvvwngK4Lo3mRKE29RRx3Jb5c"); Console.WriteLine(); } @@ -788,6 +792,9 @@ private static async Task PreFlightChecks(IServiceProvider services) // Configure Etchash Miningcore.Crypto.Hashing.Ethash.Etchash.Cache.messageBus = messageBus; + + // Configure Ethashb3 + Miningcore.Crypto.Hashing.Ethash.Ethashb3.Cache.messageBus = messageBus; // Configure Ubqhash Miningcore.Crypto.Hashing.Ethash.Ubqhash.Cache.messageBus = messageBus; @@ -804,6 +811,18 @@ private static async Task PreFlightChecks(IServiceProvider services) // Configure RandomARQ RandomARQ.messageBus = messageBus; + + // Configure NexaPow + Miningcore.Crypto.Hashing.Algorithms.NexaPow.messageBus = messageBus; + + // Configure BeamHash + BeamHash.messageBus = messageBus; + + // Configure FiroPow + Miningcore.Crypto.Hashing.Progpow.Firopow.Cache.messageBus = messageBus; + + // Configure Kawpow + Miningcore.Crypto.Hashing.Progpow.Kawpow.Cache.messageBus = messageBus; } private static async Task ConfigurePostgresCompatibilityOptions(IServiceProvider services) diff --git a/src/Miningcore/Util/ActionUtils.cs b/src/Miningcore/Util/ActionUtils.cs index e80a727f2..774934c3e 100644 --- a/src/Miningcore/Util/ActionUtils.cs +++ b/src/Miningcore/Util/ActionUtils.cs @@ -40,6 +40,21 @@ public static void Guard(Action func, Action errorHandler = null) errorHandler?.Invoke(ex); } } + + public static async Task Guard(Task task, Action errorHandler = null) + { + try + { + return await task; + } + + catch (Exception ex) + { + errorHandler?.Invoke(ex); + + return default; + } + } public static async Task Guard(Func> func, Action errorHandler = null) { diff --git a/src/Miningcore/build-libs-linux.sh b/src/Miningcore/build-libs-linux.sh index a65082c85..90a6efd49 100755 --- a/src/Miningcore/build-libs-linux.sh +++ b/src/Miningcore/build-libs-linux.sh @@ -6,21 +6,23 @@ 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) SSSE3=$(../Native/check_cpu.sh ssse3 && echo -mssse3 || echo) +PCLMUL=$(../Native/check_cpu.sh pclmul && echo -mpclmul || echo) AVX=$(../Native/check_cpu.sh avx && echo -mavx || echo) AVX2=$(../Native/check_cpu.sh avx2 && echo -mavx2 || echo) AVX512F=$(../Native/check_cpu.sh avx512f && echo -mavx512f || echo) -export CPU_FLAGS="$AES $SSE2 $SSE3 $SSSE3 $AVX $AVX2 $AVX512F" +export CPU_FLAGS="$AES $SSE2 $SSE3 $SSSE3 $PCLMUL $AVX $AVX2 $AVX512F" HAVE_AES=$(../Native/check_cpu.sh aes && echo -D__AES__ || echo) HAVE_SSE2=$(../Native/check_cpu.sh sse2 && echo -DHAVE_SSE2 || echo) HAVE_SSE3=$(../Native/check_cpu.sh sse3 && echo -DHAVE_SSE3 || echo) HAVE_SSSE3=$(../Native/check_cpu.sh ssse3 && echo -DHAVE_SSSE3 || echo) +HAVE_PCLMUL=$(../Native/check_cpu.sh pclmul && echo -DHAVE_PCLMUL || echo) HAVE_AVX=$(../Native/check_cpu.sh avx && echo -DHAVE_AVX || echo) HAVE_AVX2=$(../Native/check_cpu.sh avx2 && echo -DHAVE_AVX2 || echo) HAVE_AVX512F=$(../Native/check_cpu.sh avx512f && echo -DHAVE_AVX512F || echo) -export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_AVX $HAVE_AVX2 $HAVE_AVX512F" +export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_PCLMUL $HAVE_AVX $HAVE_AVX2 $HAVE_AVX512F" (cd ../Native/libmultihash && make clean && make) && mv ../Native/libmultihash/libmultihash.so "$OutDir" (cd ../Native/libbeamhash && make clean && make) && mv ../Native/libbeamhash/libbeamhash.so "$OutDir" @@ -34,5 +36,6 @@ export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_AVX $HAVE (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 /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") diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index 9491026fe..45ca5fec5 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -1766,6 +1766,27 @@ "explorerTxLink": "https://explorer.namecoin.info/tx/{0}", "explorerAccountLink": "https://explorer.namecoin.info/a/{0}" }, + "nexa": { + "name": "Nexa", + "canonicalName": "Nexa", + "symbol": "NEXA", + "family": "nexa", + "website": "https://www.nexa.org/", + "github": "https://gitlab.com/nexa/nexa", + "explorer": "https://explorer.nexa.org/", + "market": "https://www.coingecko.com/en/coins/nexacoin", + "twitter": "https://twitter.com/nexamoney", + "telegram": "https://t.me/nexacoin", + "discord": "https://discord.com/invite/2yQNsZV6EJ", + "headerHasher": { + "hash": "nexapow" + }, + "explorerBlockLink": "https://explorer.nexa.org/block-height/$height$", + "explorerTxLink": "https://explorer.nexa.org/tx/{0}", + "explorerAccountLink": "https://explorer.nexa.org/address/{0}", + "forcePoolAddressDestinationWithPubKey": true, + "payoutDecimalPlaces": 2 + }, "note-blockchain": { "name": "Note Blockchain", "canonicalName": "Note-Blockchain", @@ -4327,13 +4348,14 @@ "canonicalName": "Monero", "symbol": "XMR", "family": "cryptonote", - "website": "", - "market": "", - "twitter": "", + "website": "https://www.getmonero.org/", + "market": "https://coinmarketcap.com/currencies/monero", + "twitter": "https://twitter.com/monero", "telegram": "", "discord": "", "hash": "randomx", "hashVariant": 0, + "blobType": 0, "smallestUnit": 1000000000000, "addressPrefix": 18, "addressPrefixStagenet": 24, @@ -4359,6 +4381,7 @@ "discord": "http://discord.conceal.network/", "hash": "cn-gpu", "hashVariant": 0, + "blobType": 0, "difficultyTarget": 120, "smallestUnit": 1000000, "addressPrefix": 31444, @@ -4368,6 +4391,32 @@ "explorerBlockLink": "https://explorer.conceal.network/index.html?hash=$hash$#blockchain_block", "explorerTxLink": "https://explorer.conceal.network/index.html?hash={0}#blockchain_transaction" }, + "zephyr": { + "name": "Zephyr", + "canonicalName": "Zephyr", + "symbol": "ZEPH", + "family": "cryptonote", + "website": "https://www.zephyrprotocol.com/", + "market": "https://www.coingecko.com/en/coins/zephyr-protocol", + "twitter": "https://twitter.com/zephyr_org", + "telegram": "https://t.me/zephyrprotocol", + "discord": "https://discord.gg/y4mzbDYSqQ", + "hash": "randomx", + "hashVariant": 0, + "blobType": 13, + "smallestUnit": 1000000000000, + "addressPrefix": 26375690432, + "addressPrefixTestnet": 3362369, + "addressPrefixStagenet": 3329601, + "addressPrefixIntegrated": 52873205952, + "addressPrefixIntegratedTestnet": 45352160833, + "addressPrefixIntegratedStagenet": 29241806401, + "subAddressPrefix": 148723904, + "subAddressPrefixTestnet": 253742657, + "subAddressPrefixStagenet": 249515585, + "explorerBlockLink": "https://explorer.zephyrprotocol.com/block/$height$", + "explorerTxLink": "https://explorer.zephyrprotocol.com/tx/{0}" + }, "callisto": { "name": "Callisto Network", "canonicalName": "Callisto-Network", @@ -4494,22 +4543,22 @@ "explorerAccountLink": "https://pinkscan.org/address/{0}", "ethasher": "ethash" }, - "rethereum": { - "name": "Rethereum", - "canonicalName": "Rethereum", - "symbol": "RTH", + "hypra": { + "name": "Hypra", + "canonicalName": "Hypra", + "symbol": "HYP", "family": "ethereum", - "website": "https://www.rethereum.org/", + "website": "https://www.hypra.network/", "market": "", "twitter": "", "telegram": "", "discord": "https://discord.gg/xCB4AJDEFb", "explorerBlockLinks": { - "block": "https://explorer.rethereum.org/block/$height$", - "uncle": "https://explorer.rethereum.org/block/$hash$" + "block": "https://explorer.hypra.network/block/$height$", + "uncle": "https://explorer.hypra.network/block/$hash$" }, - "explorerTxLink": "https://explorer.rethereum.org/tx/{0}", - "explorerAccountLink": "https://explorer.rethereum.org/address/{0}", + "explorerTxLink": "https://explorer.hypra.network/tx/{0}", + "explorerAccountLink": "https://explorer.hypra.network/address/{0}", "ethasher": "ethashb3" }, "ubiq": { @@ -4557,5 +4606,47 @@ "explorerBlockLink": "https://explorer.alephium.org/blocks/$hash$", "explorerTxLink": "https://explorer.alephium.org/transactions/{0}", "explorerAccountLink": "https://explorer.alephium.org/addresses/{0}" + }, + "kaspa": { + "name": "Kaspa", + "canonicalName": "Kaspa", + "symbol": "KAS", + "family": "kaspa", + "website": "https://kaspa.org/", + "market": "https://coinmarketcap.com/currencies/kaspa/", + "twitter": "https://twitter.com/KaspaCurrency", + "telegram": "https://t.me/Kaspaenglish", + "discord": "https://discord.gg/kS3SK5F36R", + "explorerBlockLink": "https://explorer.kaspa.org/blocks/$hash$", + "explorerTxLink": "https://explorer.kaspa.org/txs/{0}", + "explorerAccountLink": "https://explorer.kaspa.org/addresses/{0}" + }, + "karlsencoin": { + "name": "Karlsencoin", + "canonicalName": "Karlsencoin", + "symbol": "KLS", + "family": "kaspa", + "website": "https://karlsencoin.com/", + "market": "", + "twitter": "https://twitter.com/karlsennetwork", + "telegram": "https://t.me/KarlsenNetwork", + "discord": "https://discord.com/invite/NasfjsEm", + "explorerBlockLink": "https://explorer.karlsencoin.com/blocks/$hash$", + "explorerTxLink": "https://explorer.karlsencoin.com/txs/{0}", + "explorerAccountLink": "https://explorer.karlsencoin.com/addresses/{0}" + }, + "pyrin": { + "name": "Pyrin", + "canonicalName": "Pyrin", + "symbol": "PYI", + "family": "kaspa", + "website": "https://pyrin.network/", + "market": "", + "twitter": "https://twitter.com/pyrin_network", + "telegram": "https://t.me/pyrin_network", + "discord": "https://discord.gg/QQgWRntF", + "explorerBlockLink": "https://explorer.pyrin.network/blocks/$hash$", + "explorerTxLink": "https://explorer.pyrin.network/txs/{0}", + "explorerAccountLink": "https://explorer.pyrin.network/addresses/{0}" } } diff --git a/src/Native/check_cpu.sh b/src/Native/check_cpu.sh index 7868551ca..475ee9264 100755 --- a/src/Native/check_cpu.sh +++ b/src/Native/check_cpu.sh @@ -2,40 +2,48 @@ set -e QUERY="$1" check_mac() { - case "$1" in - aes) sysctl -n machdep.cpu.features | grep -i aes >/dev/null;; - avx) sysctl -n machdep.cpu.features | grep -i avx >/dev/null;; - avx2) sysctl -n machdep.cpu.features | grep -i avx2 >/dev/null;; - amd) sysctl -n machdep.cpu.vendor | grep -i amd >/dev/null;; - amdnew) sysctl -n machdep.cpu.vendor | grep -i amd && test `sysctl -n machdep.cpu.family` -ge 23;; - intel) sysctl -n machdep.cpu.vendor | grep -i intel >/dev/null;; - sse2) sysctl -n machdep.cpu.features | grep -i sse2 >/dev/null;; - sse3) sysctl -n machdep.cpu.features | grep -i sse3 >/dev/null;; - ssse3) sysctl -n machdep.cpu.features | grep -i ssse3 >/dev/null;; - avx512f) sysctl -n machdep.cpu.features | grep -i avx512f >/dev/null;; - xop) sysctl -n machdep.cpu.features | grep -i xop >/dev/null;; - *) echo "UNRECOGNISED CHECK $QUERY"; exit 1; ;; - esac + case "$1" in + aes) sysctl -n machdep.cpu.features | grep -i aes >/dev/null ;; + avx) sysctl -n machdep.cpu.features | grep -i avx >/dev/null ;; + avx2) sysctl -n machdep.cpu.features | grep -i avx2 >/dev/null ;; + amd) sysctl -n machdep.cpu.vendor | grep -i amd >/dev/null ;; + amdnew) sysctl -n machdep.cpu.vendor | grep -i amd && test $(sysctl -n machdep.cpu.family) -ge 23 ;; + intel) sysctl -n machdep.cpu.vendor | grep -i intel >/dev/null ;; + sse2) sysctl -n machdep.cpu.features | grep -i sse2 >/dev/null ;; + sse3) sysctl -n machdep.cpu.features | grep -i sse3 >/dev/null ;; + ssse3) sysctl -n machdep.cpu.features | grep -i ssse3 >/dev/null ;; + pclmul) grep -w 'pclmulqdq' /proc/cpuinfo >/dev/null ;; + avx512f) sysctl -n machdep.cpu.features | grep -i avx512f >/dev/null ;; + xop) sysctl -n machdep.cpu.features | grep -i xop >/dev/null ;; + *) + echo "UNRECOGNISED CHECK $QUERY" + exit 1 + ;; + esac } check_linux() { - case "$1" in - aes) grep -w 'aes' /proc/cpuinfo >/dev/null;; - avx) grep -w 'avx' /proc/cpuinfo >/dev/null;; - avx2) grep -w 'avx2' /proc/cpuinfo >/dev/null;; - amd) grep -i amd /proc/cpuinfo >/dev/null;; - amdnew) grep -i amd /proc/cpuinfo >/dev/null && test `awk '/cpu family/ && $NF~/^[0-9]*$/ {print $NF}' /proc/cpuinfo | head -n1` -ge 23 >/dev/null;; - intel) grep -i intel /proc/cpuinfo >/dev/null;; - sse2) grep -w 'sse2' /proc/cpuinfo >/dev/null;; - sse3) grep -w 'sse3' /proc/cpuinfo >/dev/null;; - ssse3) grep -w 'ssse3' /proc/cpuinfo >/dev/null;; - avx512f) grep -w 'avx512f' /proc/cpuinfo >/dev/null;; - xop) grep -w 'xop' /proc/cpuinfo >/dev/null;; - *) echo "UNRECOGNISED CHECK $QUERY"; exit 1; ;; - esac + case "$1" in + aes) grep -w 'aes' /proc/cpuinfo >/dev/null ;; + avx) grep -w 'avx' /proc/cpuinfo >/dev/null ;; + avx2) grep -w 'avx2' /proc/cpuinfo >/dev/null ;; + amd) grep -i amd /proc/cpuinfo >/dev/null ;; + amdnew) grep -i amd /proc/cpuinfo >/dev/null && test $(awk '/cpu family/ && $NF~/^[0-9]*$/ {print $NF}' /proc/cpuinfo | head -n1) -ge 23 >/dev/null ;; + intel) grep -i intel /proc/cpuinfo >/dev/null ;; + sse2) grep -w 'sse2' /proc/cpuinfo >/dev/null ;; + sse3) grep -w 'sse3' /proc/cpuinfo >/dev/null ;; + ssse3) grep -w 'ssse3' /proc/cpuinfo >/dev/null ;; + pclmul) grep -w 'pclmulqdq' /proc/cpuinfo >/dev/null ;; + avx512f) grep -w 'avx512f' /proc/cpuinfo >/dev/null ;; + xop) grep -w 'xop' /proc/cpuinfo >/dev/null ;; + *) + echo "UNRECOGNISED CHECK $QUERY" + exit 1 + ;; + esac } case "$(uname -a)" in - Darwin*) check_mac "$QUERY" ;; - *) check_linux "$QUERY" ;; -esac +Darwin*) check_mac "$QUERY" ;; +*) check_linux "$QUERY" ;; +esac \ No newline at end of file diff --git a/src/Native/libbeamhash/crypto/blake/sse/blake2.h b/src/Native/libbeamhash/crypto/blake/sse/blake2.h index 397fef422..501202258 100644 --- a/src/Native/libbeamhash/crypto/blake/sse/blake2.h +++ b/src/Native/libbeamhash/crypto/blake/sse/blake2.h @@ -64,7 +64,7 @@ extern "C" { uint8_t personal[BLAKE2S_PERSONALBYTES]; // 32 } blake2s_param; - ALIGN( 64 ) typedef struct __blake2s_state + typedef struct ALIGN( 64 ) __blake2s_state { uint32_t h[8]; uint32_t t[2]; @@ -89,7 +89,7 @@ extern "C" { uint8_t personal[BLAKE2B_PERSONALBYTES]; // 64 } blake2b_param; - ALIGN( 64 ) typedef struct __blake2b_state + typedef struct ALIGN( 64 ) __blake2b_state { uint64_t h[8]; uint8_t buf[BLAKE2B_BLOCKBYTES]; @@ -98,7 +98,7 @@ extern "C" { uint8_t lastblock; } blake2b_state; - ALIGN( 64 ) typedef struct __blake2sp_state + typedef struct ALIGN( 64 ) __blake2sp_state { blake2s_state S[8][1]; blake2s_state R[1]; @@ -106,7 +106,7 @@ extern "C" { size_t buflen; } blake2sp_state; - ALIGN( 64 ) typedef struct __blake2bp_state + typedef struct ALIGN( 64 ) __blake2bp_state { blake2b_state S[4][1]; blake2b_state R[1]; diff --git a/src/Native/libcryptonote/Makefile b/src/Native/libcryptonote/Makefile index c40fb1833..ec0119c7e 100644 --- a/src/Native/libcryptonote/Makefile +++ b/src/Native/libcryptonote/Makefile @@ -14,7 +14,8 @@ OBJECTS = exports.o \ crypto/crypto-ops-data.o \ crypto/hash.o \ crypto/keccak.o \ - common/base58.o + common/base58.o \ + zephyr_oracle/pricing_record.o all: $(TARGET) diff --git a/src/Native/libcryptonote/Makefile.MSys2 b/src/Native/libcryptonote/Makefile.MSys2 index 35b9cfb7b..7970e95be 100644 --- a/src/Native/libcryptonote/Makefile.MSys2 +++ b/src/Native/libcryptonote/Makefile.MSys2 @@ -20,6 +20,7 @@ OBJECTS = exports.o \ crypto/hash.o \ crypto/keccak.o \ common/base58.o \ + zephyr_oracle/pricing_record.o \ mingw_stubs.o all: $(TARGET) diff --git a/src/Native/libcryptonote/cryptonote_config.h b/src/Native/libcryptonote/cryptonote_config.h index aff6d2f81..06b3beb02 100644 --- a/src/Native/libcryptonote/cryptonote_config.h +++ b/src/Native/libcryptonote/cryptonote_config.h @@ -2,13 +2,16 @@ #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 // UNLOCK TIMES #define TX_V6_OFFSHORE_UNLOCK_BLOCKS 21*720 // 21 day unlock time #define TX_V6_ONSHORE_UNLOCK_BLOCKS 360 // 12 hour unlock time +#define TX_V7_ONSHORE_UNLOCK_BLOCKS 21*720 // 21 day unlock time #define TX_V6_XASSET_UNLOCK_BLOCKS 1440 // 2 day unlock time #define TX_V6_OFFSHORE_UNLOCK_BLOCKS_TESTNET 60 // 2 hour unlock time - FOR TESTING ONLY #define TX_V6_ONSHORE_UNLOCK_BLOCKS_TESTNET 30 // 1 hour unlock time - FOR TESTING ONLY @@ -30,4 +33,5 @@ enum BLOB_TYPE { BLOB_TYPE_CRYPTONOTE_TUBE = 10, // TUBE BLOB_TYPE_CRYPTONOTE_XHV = 11, // Haven BLOB_TYPE_CRYPTONOTE_XTA = 12, // ITALO + BLOB_TYPE_CRYPTONOTE_ZEPHYR = 13, // ZEPHYR }; diff --git a/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h b/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h index c3b9277ea..da8ff08bc 100644 --- a/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h +++ b/src/Native/libcryptonote/cryptonote_core/cryptonote_basic.h @@ -16,6 +16,7 @@ #include "serialization/binary_archive.h" #include "serialization/crypto.h" #include "serialization/pricing_record.h" +#include "serialization/zephyr_pricing_record.h" #include "serialization/keyvalue_serialization.h" // eepe named serialization #include "string_tools.h" #include "cryptonote_config.h" @@ -26,6 +27,7 @@ #include "ringct/rctTypes.h" #include "cryptonote_protocol/blobdatatype.h" #include "offshore/pricing_record.h" +#include "zephyr_oracle/pricing_record.h" namespace cryptonote @@ -107,6 +109,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 @@ -199,12 +217,29 @@ namespace cryptonote FIELD(k_image) END_SERIALIZE() }; + + struct txin_zephyr_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() + }; - typedef boost::variant txin_v; + typedef boost::variant txin_v; typedef boost::variant txout_target_v; typedef boost::variant txout_xhv_target_v; + typedef boost::variant txout_stablero_target_v; + struct tx_out { uint64_t amount; @@ -227,6 +262,17 @@ namespace cryptonote END_SERIALIZE() }; + struct tx_out_zephyr + { + uint64_t amount; + txout_stablero_target_v target; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(amount) + FIELD(target) + END_SERIALIZE() + }; + enum loki_version { @@ -249,6 +295,7 @@ namespace cryptonote std::vector vin; std::vector vout; std::vector vout_xhv; + std::vector vout_zephyr; //extra std::vector extra; // Block height to use PR from @@ -257,11 +304,12 @@ namespace cryptonote std::vector offshore_data; uint64_t amount_burnt; uint64_t amount_minted; + std::vector output_unlock_times; + std::vector collateral_indices; // // NOTE: Loki specific // - std::vector output_unlock_times; enum loki_type_t { loki_type_standard, @@ -287,10 +335,14 @@ namespace cryptonote if (blob_type != BLOB_TYPE_CRYPTONOTE_XHV || version < POU_TRANSACTION_VERSION) VARINT_FIELD(unlock_time) FIELD(vin) - if (blob_type != BLOB_TYPE_CRYPTONOTE_XHV) - FIELD(vout) - 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; @@ -301,6 +353,11 @@ namespace cryptonote 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 (blob_type == BLOB_TYPE_CRYPTONOTE_XHV && version >= OFFSHORE_TRANSACTION_VERSION) { VARINT_FIELD(pricing_record_height) if (version < 5) @@ -312,6 +369,16 @@ namespace cryptonote 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() @@ -370,23 +437,25 @@ namespace cryptonote if (!vin.empty()) { ar.begin_object(); - bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? vout.size() : vout_xhv.size()); + bool r = rct_signatures.serialize_rctsig_base(ar, 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_XHV) { - 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); - } 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 : - 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); } if (!r || !ar.stream().good()) return false; ar.end_object(); @@ -419,6 +488,7 @@ namespace cryptonote vin.clear(); vout.clear(); vout_xhv.clear(); + vout_zephyr.clear(); extra.clear(); signatures.clear(); pricing_record_height = 0; @@ -426,6 +496,7 @@ namespace cryptonote amount_burnt = 0; amount_minted = 0; output_unlock_times.clear(); + collateral_indices.clear(); } inline @@ -440,6 +511,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_zephyr_key& txin) const {return txin.key_offsets.size();} }; return boost::apply_visitor(txin_signature_size_visitor(), tx_in); @@ -560,6 +632,7 @@ namespace cryptonote uint64_t nonce; uint64_t nonce8; offshore::pricing_record pricing_record; + zephyr_oracle::pricing_record zephyr_pricing_record; crypto::cycle cycle; crypto::cycle40 cycle40; crypto::cycle48 cycle48; @@ -585,6 +658,27 @@ namespace cryptonote if (blob_type == BLOB_TYPE_CRYPTONOTE_XTA) FIELD(cycle48) if (blob_type == BLOB_TYPE_CRYPTONOTE_XHV) FIELD(pricing_record) + if (blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { + if (major_version >= 3) + { + FIELD_N("pricing_record", zephyr_pricing_record) + } + else + { + zephyr_oracle::pricing_record_v1 pr_v1; + if (!typename Archive::is_saving()) + { + FIELD(pr_v1) + pr_v1.write_to_pr(zephyr_pricing_record); + } + else + { + pr_v1.read_from_pr(zephyr_pricing_record); + FIELD(pr_v1) + } + } + } + END_SERIALIZE() }; @@ -671,12 +765,14 @@ 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_zephyr_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txin_offshore, 0x3); VARIANT_TAG(binary_archive, cryptonote::txin_onshore, 0x4); VARIANT_TAG(binary_archive, cryptonote::txin_xasset, 0x5); 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_zephyr_tagged_key, 0x2); VARIANT_TAG(binary_archive, cryptonote::txout_to_tagged_key, 0x3); VARIANT_TAG(binary_archive, cryptonote::txout_offshore, 0x3); VARIANT_TAG(binary_archive, cryptonote::txout_xasset, 0x5); diff --git a/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp index 44dfa62a0..943727f13 100644 --- a/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/Native/libcryptonote/cryptonote_core/cryptonote_format_utils.cpp @@ -185,17 +185,21 @@ namespace cryptonote { BOOST_FOREACH(const auto& in, tx.vin) { - if (tx.blob_type != BLOB_TYPE_CRYPTONOTE_XHV) { - CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: " - << in.type().name() << ", expected " << typeid(txin_to_key).name() + 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 { - 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: " + } 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)); + << ", 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; @@ -259,7 +263,7 @@ namespace cryptonote std::stringstream ss; binary_archive ba(ss); const size_t inputs = t.vin.size(); - const size_t outputs = t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size(); + const size_t outputs = 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"); cryptonote::get_blob_hash(ss.str(), hashes[1]); @@ -275,17 +279,19 @@ namespace cryptonote std::stringstream ss; binary_archive ba(ss); const size_t inputs = t.vin.size(); - const size_t outputs = t.blob_type != BLOB_TYPE_CRYPTONOTE_XHV ? t.vout.size() : t.vout_xhv.size(); + const size_t outputs = 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_XHV) { - mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : 0; - } else { + if (t.blob_type == BLOB_TYPE_CRYPTONOTE_ZEPHYR) { + 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 : - 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 : + 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; } bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin); CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable"); diff --git a/src/Native/libcryptonote/exports.cpp b/src/Native/libcryptonote/exports.cpp index 2352d0035..168816db2 100644 --- a/src/Native/libcryptonote/exports.cpp +++ b/src/Native/libcryptonote/exports.cpp @@ -19,14 +19,16 @@ using namespace cryptonote; extern "C" void cn_fast_hash(const void* data, size_t length, char* hash); -extern "C" MODULE_API bool convert_blob_export(const char* input, unsigned int inputSize, unsigned char *output, unsigned int *outputSize) +extern "C" MODULE_API bool convert_blob_export(const char* input, unsigned int inputSize, unsigned char *output, unsigned int *outputSize, unsigned int blobType) { unsigned int originalOutputSize = *outputSize; + enum BLOB_TYPE blob_type = static_cast((int) blobType); blobdata input_blob = std::string(input, inputSize); blobdata result = ""; block block = AUTO_VAL_INIT(block); + block.set_blob_type(blob_type); if (!parse_and_validate_block_from_blob(input_blob, block)) { *outputSize = 0; @@ -46,6 +48,28 @@ extern "C" MODULE_API bool convert_blob_export(const char* input, unsigned int i return true; } +extern "C" MODULE_API bool get_block_id_export(const char* input, unsigned int inputSize, unsigned char *output, unsigned int blobType) +{ + enum BLOB_TYPE blob_type = static_cast((int) blobType); + + blobdata input_blob = std::string(input, inputSize); + crypto::hash block_id; + + block block = AUTO_VAL_INIT(block); + block.set_blob_type(blob_type); + if (!parse_and_validate_block_from_blob(input_blob, block)) + return false; + + if (!get_block_hash(block, block_id)) + return false; + + char *cstr = reinterpret_cast(&block_id); + + // success + memcpy(output, cstr, 32); + return true; +} + extern "C" MODULE_API uint64_t decode_address_export(const char* input, unsigned int inputSize) { blobdata input_blob = std::string(input, inputSize); diff --git a/src/Native/libcryptonote/serialization/zephyr_pricing_record.h b/src/Native/libcryptonote/serialization/zephyr_pricing_record.h new file mode 100644 index 000000000..df8302fc9 --- /dev/null +++ b/src/Native/libcryptonote/serialization/zephyr_pricing_record.h @@ -0,0 +1,126 @@ +// Copyright (c) 2019, Haven Protocol +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include + +#include "serialization.h" +#include "zephyr_oracle/pricing_record.h" +#include "cryptonote_config.h" + +// read +template

@(=2*v+<(L0X#Qy33zxidsPrbnYj~hx~ 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 Kh! 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 NM;)UYY$``j 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�A;$+Z_49janZ*~o9-u3Y$om%V{uSysl~Qh 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