├── MoneroKit ├── Metal │ ├── MetalGranularity.h │ ├── u64.metal │ ├── MoneroBackendMetalThread.h │ ├── mul128.metal │ ├── stage3_0.metal │ ├── stage4.metal │ ├── stage5.metal │ ├── stage3_1.metal │ ├── stage1.metal │ ├── stage2.metal │ ├── keccak.metal │ ├── aes.metal │ └── stage3_2.metal ├── NSData+hex.h ├── CPU │ ├── MoneroBackendCPUThread.h │ ├── crypto │ │ ├── keccak.h │ │ ├── jh.h │ │ ├── hash-extra-blake.c │ │ ├── hash-extra-groestl.c │ │ ├── hash-extra-skein.c │ │ ├── skein.h │ │ ├── hash-extra-jh.c │ │ ├── int-util.h │ │ ├── hash-ops.h │ │ ├── blake256.h │ │ ├── groestl.h │ │ ├── keccak.c │ │ ├── groestl_tables.h │ │ ├── skein_port.h │ │ ├── groestl.c │ │ ├── blake256.c │ │ └── variant4_random_math.h │ └── MoneroBackendCPUThread.m ├── MoneroBackend_private.h ├── Info.plist ├── NSData+hex.m ├── MoneroBackend.h ├── MoneroPoolConnection.h ├── MoneroBackendJob.m ├── MoneroBackend.m ├── MoneroWorker.m ├── MoneroMiner.m ├── MoneroKit.h └── MoneroPoolConnection.m ├── MoneroKit.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── MoneroKit.xcscheme ├── MoneroKitSample ├── iOS │ ├── AppDelegate.h │ ├── main.m │ ├── AppDelegate.m │ ├── Info.plist │ ├── LaunchScreen.storyboard │ ├── ViewController.m │ └── Main.storyboard └── OSX-Swift │ └── main.swift ├── LICENSE.md └── README.md /MoneroKit/Metal/MetalGranularity.h: -------------------------------------------------------------------------------- 1 | #define GRANULARITY 16 2 | -------------------------------------------------------------------------------- /MoneroKit/Metal/u64.metal: -------------------------------------------------------------------------------- 1 | typedef size_t _uint64_t; 2 | static_assert(sizeof(_uint64_t) == 8, "Invalid uint64 size"); 3 | -------------------------------------------------------------------------------- /MoneroKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MoneroKit/NSData+hex.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+hex.h 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 21.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | NSData *_mm_dataFromHexString(NSString *hex); 12 | NSString *_mm_hexStringFromData(NSData *data); 13 | -------------------------------------------------------------------------------- /MoneroKitSample/iOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MoneroKitSample-iOS 4 | // 5 | // Created by Yury Popov on 10.01.2018. 6 | // 7 | 8 | @import UIKit; 9 | 10 | @interface AppDelegate : UIResponder 11 | 12 | @property (strong, nonatomic) UIWindow *window; 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /MoneroKitSample/iOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MoneroKitSample-iOS 4 | // 5 | // Created by Yury Popov on 10.01.2018. 6 | // 7 | 8 | @import UIKit; 9 | #import "AppDelegate.h" 10 | 11 | int main(int argc, char * argv[]) { 12 | @autoreleasepool { 13 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MoneroKitSample/iOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MoneroKitSample-iOS 4 | // 5 | // Created by Yury Popov on 10.01.2018. 6 | // 7 | 8 | #import "AppDelegate.h" 9 | 10 | @implementation AppDelegate 11 | 12 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 13 | return YES; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /MoneroKit/CPU/MoneroBackendCPUThread.h: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroBackendCPUThread.h 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 21.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | @class MoneroBackend; 12 | 13 | @interface MoneroBackendCPUThread: NSThread 14 | @property (atomic, weak) MoneroBackend *backend; 15 | @property (nonatomic, readonly) double hashRate; 16 | @end 17 | -------------------------------------------------------------------------------- /MoneroKit/Metal/MoneroBackendMetalThread.h: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroBackendMetalThread.h 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 23.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | @import Metal; 11 | 12 | @class MoneroBackend; 13 | 14 | @interface MoneroBackendMetalThread : NSThread 15 | @property (atomic, weak) MoneroBackend *backend; 16 | @property (nonatomic, readonly) double hashRate; 17 | @property (atomic, strong) id device; 18 | @end 19 | -------------------------------------------------------------------------------- /MoneroKit/MoneroBackend_private.h: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroBackend_private.h 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 21.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroBackend.h" 10 | 11 | @interface MoneroBackend () 12 | @property (atomic) NSArray *threadPool; 13 | @property (atomic) _Atomic(uint32_t) nonce; 14 | - (void)handleResult:(const struct MoneroHash*)hash withNonce:(uint32_t)nonce forJob:(NSString*)jobId; 15 | - (uint32_t)nextNonceBlock:(uint32_t)count; 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /MoneroKit/Metal/mul128.metal: -------------------------------------------------------------------------------- 1 | static inline __attribute__((always_inline)) void mul128(const uint2 ca, const uint2 cb, thread uint4 &cres) { 2 | _uint64_t ltmp[4]; 3 | thread uint32_t *tmp = (thread uint32_t*)ltmp; 4 | 5 | _uint64_t A = ca.y; 6 | _uint64_t a = ca.x; 7 | _uint64_t B = cb.y; 8 | _uint64_t b = cb.x; 9 | 10 | ltmp[0] = a * b; 11 | ltmp[1] = a * B; 12 | ltmp[2] = A * b; 13 | ltmp[3] = A * B; 14 | 15 | ltmp[1] += tmp[1]; 16 | ltmp[1] += tmp[4]; 17 | ltmp[3] += tmp[3]; 18 | ltmp[3] += tmp[5]; 19 | cres = uint4(tmp[6], tmp[7], tmp[0], tmp[2]); 20 | } 21 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/keccak.h: -------------------------------------------------------------------------------- 1 | // keccak.h 2 | // 19-Nov-11 Markku-Juhani O. Saarinen 3 | 4 | #ifndef KECCAK_H 5 | #define KECCAK_H 6 | 7 | #include 8 | #include 9 | 10 | #ifndef KECCAK_ROUNDS 11 | #define KECCAK_ROUNDS 24 12 | #endif 13 | 14 | #ifndef ROTL64 15 | #define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) 16 | #endif 17 | 18 | // compute a keccak hash (md) of given byte length from "in" 19 | void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen); 20 | 21 | // update the state 22 | void keccakf(uint64_t st[25], int norounds); 23 | 24 | void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /MoneroKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/jh.h: -------------------------------------------------------------------------------- 1 | /*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C 2 | 3 | -------------------------------- 4 | Performance 5 | 6 | Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz) 7 | Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic) 8 | Speed for long message: 9 | 1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2 10 | 2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3 11 | 12 | -------------------------------- 13 | Last Modified: January 16, 2011 14 | */ 15 | #pragma once 16 | 17 | typedef unsigned char BitSequence; 18 | typedef unsigned long long DataLength; 19 | typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn; 20 | 21 | HashReturn jh_hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval); 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | © 2018 Yury Popov _a.k.a. PhoeniX_ 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. 8 | -------------------------------------------------------------------------------- /MoneroKit/NSData+hex.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+hex.m 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 21.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "NSData+hex.h" 10 | 11 | NSData *_mm_dataFromHexString(NSString *hex) { 12 | if ((hex.length % 2) != 0) return nil; 13 | NSMutableData *data = [[NSMutableData alloc] initWithLength:hex.length / 2]; 14 | unsigned char *dbytes = [data mutableBytes]; 15 | char b[3] = {0,0,0}, *e; 16 | for (size_t i = 0; i < hex.length / 2; i++) { 17 | b[0] = (char)[hex characterAtIndex:i*2]; 18 | b[1] = (char)[hex characterAtIndex:i*2+1]; 19 | dbytes[i] = (unsigned char)strtoul(b, &e, 16); 20 | if (e != &b[2]) return nil; 21 | } 22 | return [[NSData alloc] initWithData:data]; 23 | } 24 | 25 | NSString *_mm_hexStringFromData(NSData *data) { 26 | const unsigned char *dbytes = [data bytes]; 27 | NSMutableString *hexStr = [NSMutableString stringWithCapacity:[data length]*2]; 28 | for (size_t i = 0; i < [data length]; i++) { 29 | [hexStr appendFormat:@"%02x", dbytes[i]]; 30 | } 31 | return [NSString stringWithString: hexStr]; 32 | } 33 | -------------------------------------------------------------------------------- /MoneroKitSample/OSX-Swift/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // MoneroKitSample-OSX-Swift 4 | // 5 | // Created by Yury Popov on 10.01.2018. 6 | // 7 | 8 | import Foundation 9 | import MoneroKit 10 | 11 | class Delegate: MoneroMinerDelegate { 12 | func acceptedResult(_ result: UInt, forWorker workerId: String) { 13 | print("Result: \(result)") 14 | } 15 | 16 | func difficultyChanged(_ difficulty: UInt, forWorker workerId: String) { 17 | print("Difficulty: \(difficulty)") 18 | } 19 | 20 | func blockFound(forWorker workerId: String) { 21 | print("New block") 22 | } 23 | 24 | func miningError(_ error: Error, stopped: Bool) { 25 | print("Error: \(error)\(stopped ? " (mining stopped)" : "")") 26 | } 27 | } 28 | 29 | let delegate = Delegate() 30 | 31 | let worker = MoneroWorker( 32 | identifier: "default", 33 | poolHost: "moneropool.phoenix.dj", 34 | port: 7777, 35 | secure: false, 36 | walletAddress: "", 37 | password: "x", 38 | weight: 1 39 | ) 40 | 41 | let miner = MoneroMiner() 42 | miner.workers = [worker] 43 | miner.cpuLimit = 1 44 | miner.metalLimit = 0.9 45 | miner.delegate = delegate 46 | miner.startMining() 47 | 48 | while miner.active { 49 | Thread.sleep(forTimeInterval: 1) 50 | print("Hash rate: \(String(format: "%.01f", miner.hashRate))") 51 | } 52 | -------------------------------------------------------------------------------- /MoneroKitSample/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /MoneroKit/Metal/stage3_0.metal: -------------------------------------------------------------------------------- 1 | // 2 | // stage3.metal 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 25.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #include "u64.metal" 13 | #include "aes.metal" 14 | #include "mul128.metal" 15 | 16 | constant static const constexpr size_t threadMemorySize = 1 << 21; 17 | constant static const constexpr size_t stateSize = 320; 18 | constant static const constexpr size_t ITER = (1 << 20); 19 | 20 | #include "MetalGranularity.h" 21 | 22 | kernel void cn_stage3_n_v0( 23 | device uint8_t *statebuf [[ buffer(0) ]], 24 | device uint8_t *membuf [[ buffer(1) ]], 25 | uint idx [[ thread_position_in_grid ]] 26 | ) 27 | { 28 | device uint8_t *state = (statebuf + idx * stateSize); 29 | device uint8_t *long_state = (membuf + idx * threadMemorySize); 30 | device uint4 *_a = (device uint4*)(state + 208); 31 | device uint4 *_b = (device uint4*)(state + 224); 32 | device uint4 *p; 33 | 34 | uint4 a = *_a, b = *_b, c, t; 35 | 36 | for(size_t i = 0; i < ITER / 2 / GRANULARITY; i++) { 37 | // Iteration 1 38 | p = (device uint4*)&long_state[a.x & 0x1ffff0]; 39 | c = *p; 40 | aes_round(c, a); 41 | b ^= c; 42 | *p = b; 43 | 44 | // Iteration 2 45 | p = (device uint4*)&long_state[c.x & 0x1ffff0]; 46 | b = *p; 47 | mul128(*(thread uint2*)&c, *(thread uint2*)&b, t); 48 | ((thread _uint64_t*)&a)[0] += ((const thread _uint64_t*)&t)[0]; 49 | ((thread _uint64_t*)&a)[1] += ((const thread _uint64_t*)&t)[1]; 50 | *p = a; 51 | a ^= b; 52 | b = c; 53 | } 54 | 55 | *_a = a; *_b = b; 56 | } 57 | -------------------------------------------------------------------------------- /MoneroKit/MoneroBackend.h: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroBackend.h 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 10.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | struct MoneroHash { 12 | union { 13 | uint8_t bytes[32]; 14 | uint32_t uints[8]; 15 | uint64_t lluints[4]; 16 | } __attribute((packed)); 17 | }; 18 | 19 | @interface MoneroBackendJob: NSObject 20 | @property (nonatomic, copy) NSString *jobId; 21 | @property (nonatomic, copy) NSData *blob; 22 | @property (nonatomic) uint64_t target; 23 | @property (nonatomic) BOOL nicehash; 24 | @property (nonatomic) uint64_t height; 25 | 26 | @property (nonatomic, readonly) uint64_t versionMajor; 27 | @property (nonatomic, readonly) uint64_t versionMinor; 28 | @property (nonatomic, readonly) uint64_t timestamp; 29 | @property (nonatomic, readonly) struct MoneroHash prevBlockHash; 30 | @property (nonatomic, readonly) uint32_t nonce; 31 | @property (nonatomic, readonly) ptrdiff_t nonceOffset; 32 | @property (nonatomic, readonly) struct MoneroHash merkleRootHash; 33 | @property (nonatomic, readonly) uint64_t transactionsCount; 34 | 35 | @property (nonatomic, readonly) uint64_t difficulty; 36 | @end 37 | 38 | @protocol MoneroBackendDelegate 39 | - (void)foundResult:(const struct MoneroHash*)result withNonce:(uint32_t)nonce forJobId:(NSString*)job; 40 | @end 41 | 42 | @interface MoneroBackend: NSObject 43 | - (instancetype)init; 44 | @property (nonatomic, readwrite, setter=setCPULimit:) double cpuLimit; 45 | @property (nonatomic, readwrite) double metalLimit; 46 | @property (nonatomic, readwrite) MoneroBackendJob *currentJob; 47 | @property (nonatomic, readwrite) dispatch_queue_t delegateQueue; 48 | @property (nonatomic, weak, readwrite) id delegate; 49 | @property (nonatomic, readonly) double hashRate; 50 | @end 51 | -------------------------------------------------------------------------------- /MoneroKit/MoneroPoolConnection.h: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroPoolConnection.h 3 | // MoneroKit 4 | // 5 | // Created by Yury Popov on 08.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroKit.h" 10 | #import "MoneroBackend.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | typedef void(^MoneroPoolConnectionCallback)(NSError *_Nullable error, NSDictionary *_Nullable result); 15 | typedef void(^MoneroPoolResultCallback)(NSError *_Nullable error); 16 | 17 | @class MoneroPoolConnection; 18 | 19 | @protocol MoneroPoolConnectionDelegate 20 | - (void)connection:(MoneroPoolConnection*)connection receivedCommand:(NSString*)command withOptions:(NSDictionary*)options callback:(MoneroPoolConnectionCallback)callback; 21 | - (void)connection:(MoneroPoolConnection*)connection receivedNewJob:(MoneroBackendJob*)job; 22 | - (void)connection:(MoneroPoolConnection*)connection error:(NSError*)error; 23 | @end 24 | 25 | @interface MoneroPoolConnection : NSObject 26 | - (instancetype)init NS_UNAVAILABLE; 27 | - (instancetype)initWithHost:(NSString*)host port:(NSInteger)port ssl:(BOOL)ssl walletAddress:(NSString*)walletAddress password:(NSString*)password; 28 | + (instancetype)connectionWithHost:(NSString*)host port:(NSInteger)port ssl:(BOOL)ssl walletAddress:(NSString*)walletAddress password:(NSString*)password; 29 | - (void)connect; 30 | - (void)close; 31 | @property (atomic, copy, nullable) NSString *identifier; 32 | @property (atomic, strong) NSRunLoop *runLoop; 33 | @property (weak, nonatomic, nullable) id delegate; 34 | - (void)sendCommand:(NSString*)command withOptions:(NSDictionary*)options callback:(MoneroPoolConnectionCallback)callback; 35 | - (void)submitShare:(const struct MoneroHash*)hash withNonce:(uint32_t)nonce forJobId:(NSString*)jobId callback:(MoneroPoolResultCallback)callback; 36 | @end 37 | 38 | NS_ASSUME_NONNULL_END 39 | -------------------------------------------------------------------------------- /MoneroKitSample/iOS/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/hash-extra-blake.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers 30 | 31 | #include 32 | #include 33 | 34 | #include "blake256.h" 35 | 36 | void hash_extra_blake(const void *data, size_t length, char *hash) { 37 | blake256_hash((uint8_t*)hash, data, length); 38 | } 39 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/hash-extra-groestl.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers 30 | 31 | #include 32 | #include 33 | 34 | #include "groestl.h" 35 | 36 | void hash_extra_groestl(const void *data, size_t length, char *hash) { 37 | groestl(data, length * 8, (uint8_t*)hash); 38 | } 39 | -------------------------------------------------------------------------------- /MoneroKit/Metal/stage4.metal: -------------------------------------------------------------------------------- 1 | // 2 | // stage4.metal 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 25.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #include "aes.metal" 13 | 14 | constant static const constexpr size_t expandedKeySize = 320; 15 | constant static const constexpr size_t threadMemorySize = 1 << 21; 16 | constant static const constexpr size_t stateSize = 320; 17 | 18 | #include "MetalGranularity.h" 19 | 20 | kernel void cn_stage4_n( 21 | device uint8_t *statebuf [[ buffer(0) ]], 22 | device uint8_t *ekeybuf [[ buffer(1) ]], 23 | device uint8_t *membuf [[ buffer(2) ]], 24 | device uint8_t *partbuf [[ buffer(3) ]], 25 | uint2 idx [[ thread_position_in_grid ]] 26 | ) 27 | { 28 | device uint4 *state = (device uint4*)(statebuf + idx.x * stateSize) + 4 + idx.y; 29 | device uint4 *expandedKey = (device uint4*)(ekeybuf + idx.x * expandedKeySize + 160); 30 | device uint4 *long_state = (device uint4*)(membuf + idx.x * threadMemorySize) + idx.y; 31 | uint32_t part = (uint32_t)(*partbuf); 32 | long_state += threadMemorySize / 128 / GRANULARITY * 8 * part; 33 | 34 | thread uint4 ek[10] = { 35 | expandedKey[0], expandedKey[1], expandedKey[2], expandedKey[3], 36 | expandedKey[4], expandedKey[5], expandedKey[6], expandedKey[7], 37 | expandedKey[8], expandedKey[9] 38 | }; 39 | 40 | uint4 buf = *state; 41 | 42 | for (uint32_t i = 0; i < threadMemorySize / 128 / GRANULARITY; i++) { 43 | buf ^= *long_state; 44 | aes_round(buf, ek[0]); 45 | aes_round(buf, ek[1]); 46 | aes_round(buf, ek[2]); 47 | aes_round(buf, ek[3]); 48 | aes_round(buf, ek[4]); 49 | aes_round(buf, ek[5]); 50 | aes_round(buf, ek[6]); 51 | aes_round(buf, ek[7]); 52 | aes_round(buf, ek[8]); 53 | aes_round(buf, ek[9]); 54 | long_state += 8; 55 | } 56 | 57 | *state = buf; 58 | } 59 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/hash-extra-skein.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers 30 | 31 | #include 32 | #include 33 | 34 | #include "hash-ops.h" 35 | #include "skein.h" 36 | 37 | void hash_extra_skein(const void *data, size_t length, char *hash) { 38 | int r = skein_hash(8 * HASH_SIZE, data, 8 * length, (uint8_t*)hash); 39 | assert(SKEIN_SUCCESS == r); 40 | } 41 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/skein.h: -------------------------------------------------------------------------------- 1 | #ifndef _SKEIN_H_ 2 | #define _SKEIN_H_ 1 3 | /************************************************************************** 4 | ** 5 | ** Interface declarations and internal definitions for Skein hashing. 6 | ** 7 | ** Source code author: Doug Whiting, 2008. 8 | ** 9 | ** This algorithm and source code is released to the public domain. 10 | ** 11 | *************************************************************************** 12 | ** 13 | ** The following compile-time switches may be defined to control some 14 | ** tradeoffs between speed, code size, error checking, and security. 15 | ** 16 | ** The "default" note explains what happens when the switch is not defined. 17 | ** 18 | ** SKEIN_DEBUG -- make callouts from inside Skein code 19 | ** to examine/display intermediate values. 20 | ** [default: no callouts (no overhead)] 21 | ** 22 | ** SKEIN_ERR_CHECK -- how error checking is handled inside Skein 23 | ** code. If not defined, most error checking 24 | ** is disabled (for performance). Otherwise, 25 | ** the switch value is interpreted as: 26 | ** 0: use assert() to flag errors 27 | ** 1: return SKEIN_FAIL to flag errors 28 | ** 29 | ***************************************************************************/ 30 | #include "skein_port.h" /* get platform-specific definitions */ 31 | 32 | typedef enum 33 | { 34 | SKEIN_SUCCESS = 0, /* return codes from Skein calls */ 35 | SKEIN_FAIL = 1, 36 | SKEIN_BAD_HASHLEN = 2 37 | } 38 | HashReturn; 39 | 40 | typedef size_t DataLength; /* bit count type */ 41 | typedef u08b_t BitSequence; /* bit stream type */ 42 | 43 | /* "all-in-one" call */ 44 | HashReturn skein_hash(int hashbitlen, const BitSequence *data, 45 | DataLength databitlen, BitSequence *hashval); 46 | 47 | #endif /* ifndef _SKEIN_H_ */ 48 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/hash-extra-jh.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "jh.h" 37 | #include "hash-ops.h" 38 | 39 | void hash_extra_jh(const void *data, size_t length, char *hash) { 40 | int r = jh_hash(HASH_SIZE * 8, data, 8 * length, (uint8_t*)hash); 41 | assert(SUCCESS == r); 42 | } 43 | -------------------------------------------------------------------------------- /MoneroKit/Metal/stage5.metal: -------------------------------------------------------------------------------- 1 | // 2 | // stage5.metal 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 03.01.2018. 6 | // Copyright © 2018 PhoeniX. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #include "keccak.metal" 13 | 14 | constant static const constexpr size_t stateSize = 320; 15 | 16 | kernel void cn_stage5( 17 | device uint8_t *statebuf [[ buffer(0) ]], 18 | uint idx [[ thread_position_in_grid ]] 19 | ) 20 | { 21 | device uint8_t *state = (statebuf + idx * stateSize); 22 | state_t st; 23 | ((thread uint4*)st)[0] = ((device uint4*)state)[0]; 24 | ((thread uint4*)st)[1] = ((device uint4*)state)[1]; 25 | ((thread uint4*)st)[2] = ((device uint4*)state)[2]; 26 | ((thread uint4*)st)[3] = ((device uint4*)state)[3]; 27 | ((thread uint4*)st)[4] = ((device uint4*)state)[4]; 28 | ((thread uint4*)st)[5] = ((device uint4*)state)[5]; 29 | ((thread uint4*)st)[6] = ((device uint4*)state)[6]; 30 | ((thread uint4*)st)[7] = ((device uint4*)state)[7]; 31 | ((thread uint4*)st)[8] = ((device uint4*)state)[8]; 32 | ((thread uint4*)st)[9] = ((device uint4*)state)[9]; 33 | ((thread uint4*)st)[10] = ((device uint4*)state)[10]; 34 | ((thread uint4*)st)[11] = ((device uint4*)state)[11]; 35 | ((thread uint2*)st)[24] = ((device uint2*)state)[24]; 36 | keccakf(st, 24); 37 | ((device uint4*)state)[0] = ((thread uint4*)st)[0]; 38 | ((device uint4*)state)[1] = ((thread uint4*)st)[1]; 39 | ((device uint4*)state)[2] = ((thread uint4*)st)[2]; 40 | ((device uint4*)state)[3] = ((thread uint4*)st)[3]; 41 | ((device uint4*)state)[4] = ((thread uint4*)st)[4]; 42 | ((device uint4*)state)[5] = ((thread uint4*)st)[5]; 43 | ((device uint4*)state)[6] = ((thread uint4*)st)[6]; 44 | ((device uint4*)state)[7] = ((thread uint4*)st)[7]; 45 | ((device uint4*)state)[8] = ((thread uint4*)st)[8]; 46 | ((device uint4*)state)[9] = ((thread uint4*)st)[9]; 47 | ((device uint4*)state)[10] = ((thread uint4*)st)[10]; 48 | ((device uint4*)state)[11] = ((thread uint4*)st)[11]; 49 | ((device uint2*)state)[24] = ((thread uint2*)st)[24]; 50 | } 51 | -------------------------------------------------------------------------------- /MoneroKit/Metal/stage3_1.metal: -------------------------------------------------------------------------------- 1 | // 2 | // stage3.metal 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 25.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #include "u64.metal" 13 | #include "aes.metal" 14 | #include "mul128.metal" 15 | 16 | constant static const constexpr size_t threadMemorySize = 1 << 21; 17 | constant static const constexpr size_t stateSize = 320; 18 | constant static const constexpr size_t ITER = (1 << 20); 19 | 20 | #include "MetalGranularity.h" 21 | 22 | static constant const uint32_t v1_table = 0x75310; 23 | 24 | kernel void cn_stage3_n_v1( 25 | device uint8_t *statebuf [[ buffer(0) ]], 26 | device uint8_t *membuf [[ buffer(1) ]], 27 | uint idx [[ thread_position_in_grid ]] 28 | ) 29 | { 30 | device uint8_t *state = (statebuf + idx * stateSize); 31 | device uint8_t *long_state = (membuf + idx * threadMemorySize); 32 | device uint2 *nonceptr = (device uint2*)(state + 200); 33 | device uint4 *_a = (device uint4*)(state + 208); 34 | device uint4 *_b = (device uint4*)(state + 224); 35 | device uint4 *p; 36 | uint2 nonce = *nonceptr; 37 | 38 | uint4 a = *_a, b = *_b, c, t; 39 | 40 | uint8_t tmp, tmp0; 41 | uint32_t j; 42 | 43 | for(size_t i = 0; i < ITER / 2 / GRANULARITY; i++) { 44 | j = a.x & 0x1ffff0; 45 | // Iteration 1 46 | p = (device uint4*)&long_state[j]; 47 | c = *p; 48 | aes_round(c, a); 49 | b ^= c; 50 | *p = b; 51 | 52 | tmp = long_state[j+11]; 53 | tmp0 = (uint8_t)((((tmp >> 3) & 6) | (tmp & 1)) << 1); 54 | long_state[j+11] = tmp ^ ((v1_table >> tmp0) & 0x30); 55 | 56 | // Iteration 2 57 | 58 | j = c.x & 0x1ffff0; 59 | p = (device uint4*)&long_state[j]; 60 | b = *p; 61 | mul128(*(thread uint2*)&c, *(thread uint2*)&b, t); 62 | ((thread _uint64_t*)&a)[0] += ((const thread _uint64_t*)&t)[0]; 63 | ((thread _uint64_t*)&a)[1] += ((const thread _uint64_t*)&t)[1]; 64 | *p = a; 65 | a ^= b; 66 | *(device uint2*)(long_state + j + 8) ^= nonce; 67 | b = c; 68 | } 69 | 70 | *_a = a; *_b = b; 71 | } 72 | -------------------------------------------------------------------------------- /MoneroKit/Metal/stage1.metal: -------------------------------------------------------------------------------- 1 | // 2 | // stage1.metal 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 24.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #include "aes.metal" 13 | #include "keccak.metal" 14 | 15 | constant static const constexpr size_t blobBufferSize = 128; 16 | constant static const constexpr size_t expandedKeySize = 320; 17 | constant static const constexpr size_t stateSize = 320; 18 | 19 | kernel void cn_stage1( 20 | device uint8_t *blobbuf [[ buffer(0) ]], 21 | device uint32_t *bloblenbuf [[ buffer(1) ]], 22 | device uint8_t *statebuf [[ buffer(2) ]], 23 | device uint8_t *ekeybuf [[ buffer(3) ]], 24 | uint idx [[ thread_position_in_grid ]] 25 | ) 26 | { 27 | device uint8_t *blob = (blobbuf + idx * blobBufferSize); 28 | device uint8_t *state = (statebuf + idx * stateSize); 29 | device uint8_t *expandedKey = (ekeybuf + idx * expandedKeySize); 30 | uint32_t bloblen = *bloblenbuf; 31 | 32 | device uint2 *nonceptr = (device uint2*)(state + 200); 33 | device uint4 *a = (device uint4*)(state + 208); 34 | device uint4 *b = (device uint4*)(state + 224); 35 | device uint4 *b1 = (device uint4*)(state + 240); 36 | device uint2 *division_result = (device uint2*)(state + 256); 37 | device uint2 *sqrt_result = (device uint2*)(state + 264); 38 | 39 | keccak1600(blob, bloblen, state); 40 | 41 | *nonceptr = 0; 42 | if (bloblen >= 43) { 43 | uint2 x = ((const device uint2*)state)[24]; 44 | volatile thread uint2 y; 45 | volatile thread uint8_t *yb = (volatile thread uint8_t*)&y; 46 | yb[0] = blob[35]; 47 | yb[1] = blob[36]; 48 | yb[2] = blob[37]; 49 | yb[3] = blob[38]; 50 | yb[4] = blob[39]; 51 | yb[5] = blob[40]; 52 | yb[6] = blob[41]; 53 | yb[7] = blob[42]; 54 | *nonceptr = x^y; 55 | } 56 | 57 | aes_expand_key(expandedKey, state); 58 | aes_expand_key(expandedKey + 160, &state[32]); 59 | 60 | *a = ((device uint4*)state)[0] ^ ((device uint4*)state)[2]; 61 | *b = ((device uint4*)state)[1] ^ ((device uint4*)state)[3]; 62 | *b1 = ((device uint4*)state)[4] ^ ((device uint4*)state)[5]; 63 | 64 | *division_result = ((device uint2*)state)[12]; 65 | *sqrt_result = ((device uint2*)state)[13]; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /MoneroKit/MoneroBackendJob.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroBackendJob.m 3 | // MoneroKit 4 | // 5 | // Created by Yury Popov on 10.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroBackend.h" 10 | #import "NSData+hex.h" 11 | 12 | @implementation MoneroBackendJob { 13 | uint64_t _versionMajor; 14 | uint64_t _versionMinor; 15 | uint64_t _timestamp; 16 | struct MoneroHash _prevBlockHash; 17 | ptrdiff_t _nonceOffset; 18 | uint32_t _nonce; 19 | struct MoneroHash _merkleRootHash; 20 | uint64_t _transactionsCount; 21 | uint64_t _height; 22 | } 23 | 24 | - (void)setBlob:(NSData *)blob { 25 | if ([self parseBlob:blob]) { 26 | _blob = blob; 27 | } 28 | } 29 | 30 | static inline uint64_t read_varint(const uint8_t **buf, const uint8_t *end) { 31 | const uint8_t *p = *buf; 32 | uint8_t len = 0, tmp; 33 | uint64_t ret = 0; 34 | while (p < end) { 35 | tmp = *(p++); 36 | ret |= (uint64_t)((tmp & 0x7F) << ((len++) * 7)); 37 | if ((tmp & 0x80) == 0) break; 38 | } 39 | *buf = p; 40 | return ret; 41 | } 42 | 43 | - (BOOL)parseBlob:(NSData *)blob { 44 | const uint8_t *s = blob.bytes, *b = s, *e = b + blob.length; 45 | _versionMajor = read_varint(&b, e); 46 | _versionMinor = read_varint(&b, e); 47 | _timestamp = read_varint(&b, e); 48 | if (b + sizeof(_prevBlockHash) >= e) return NO; 49 | memcpy(&_prevBlockHash, b, sizeof(_prevBlockHash)); b += sizeof(_prevBlockHash); 50 | if (b + sizeof(_nonce) >= e) return NO; 51 | _nonceOffset = b - s; 52 | memcpy(&_nonce, b, sizeof(_nonce)); b += sizeof(_nonce); 53 | if (b + sizeof(_merkleRootHash) >= e) return NO; 54 | memcpy(&_merkleRootHash, b, sizeof(_merkleRootHash)); b += sizeof(_merkleRootHash); 55 | _transactionsCount = read_varint(&b, e); 56 | if (b != e || (*(b-1)&0x80) != 0) return NO; 57 | return YES; 58 | } 59 | 60 | - (uint64_t)difficulty { 61 | return 0xFFFFFFFFFFFFFFFFLLU / self.target; 62 | } 63 | 64 | - (NSString *)description { 65 | NSString *prevHex = _mm_hexStringFromData([NSData dataWithBytes:_prevBlockHash.bytes length:sizeof(_prevBlockHash)]); 66 | NSString *rootHex = _mm_hexStringFromData([NSData dataWithBytes:_merkleRootHash.bytes length:sizeof(_merkleRootHash)]); 67 | NSString *blobDesc = [NSString stringWithFormat:@" nonce:<%08x> root:<%@> tx:%@>", @(_versionMajor), @(_versionMinor), @(_timestamp), prevHex, _nonce, rootHex, @(_transactionsCount)]; 68 | return [NSString stringWithFormat:@" DIFF:%@ BLOB:%@>", self.jobId, @(self.difficulty), blobDesc]; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/int-util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers 30 | 31 | #pragma once 32 | 33 | #include 34 | 35 | #define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \ 36 | (((uint32_t) (x) & 0x0000ff00) << 8) | \ 37 | (((uint32_t) (x) & 0x00ff0000) >> 8) | \ 38 | (((uint32_t) (x) & 0xff000000) >> 24)) 39 | #define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \ 40 | (((uint64_t) (x) & 0x000000000000ff00) << 40) | \ 41 | (((uint64_t) (x) & 0x0000000000ff0000) << 24) | \ 42 | (((uint64_t) (x) & 0x00000000ff000000) << 8) | \ 43 | (((uint64_t) (x) & 0x000000ff00000000) >> 8) | \ 44 | (((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \ 45 | (((uint64_t) (x) & 0x00ff000000000000) >> 40) | \ 46 | (((uint64_t) (x) & 0xff00000000000000) >> 56)) 47 | 48 | #define swap32be SWAP32 49 | #define swap64be SWAP64 50 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/hash-ops.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers 30 | 31 | #pragma once 32 | 33 | #if !defined(__cplusplus) 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "int-util.h" 41 | 42 | #pragma pack(push, 1) 43 | union hash_state { 44 | uint8_t b[200]; 45 | uint64_t w[25]; 46 | }; 47 | #pragma pack(pop) 48 | static_assert(sizeof(union hash_state) == 200, "Invalid structure size"); 49 | 50 | #endif 51 | 52 | enum { 53 | HASH_SIZE = 32, 54 | HASH_DATA_AREA = 136 55 | }; 56 | 57 | void *cn_slow_hash_alloc(void); 58 | void cn_slow_hash(const void *data, size_t length, char *hash, void *ctx, uint64_t version, uint64_t height); 59 | 60 | void hash_extra_blake(const void *data, size_t length, char *hash); 61 | void hash_extra_groestl(const void *data, size_t length, char *hash); 62 | void hash_extra_jh(const void *data, size_t length, char *hash); 63 | void hash_extra_skein(const void *data, size_t length, char *hash); 64 | 65 | -------------------------------------------------------------------------------- /MoneroKit/MoneroBackend.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroBackend.m 3 | // MoneroKit 4 | // 5 | // Created by Yury Popov on 10.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroBackend_private.h" 10 | #import "MoneroBackendCPUThread.h" 11 | #import "MoneroBackendMetalThread.h" 12 | 13 | #import 14 | 15 | @implementation MoneroBackend 16 | 17 | - (instancetype)init { 18 | if (self = [super init]) { 19 | _cpuLimit = 1; 20 | _metalLimit = 1; 21 | _delegateQueue = dispatch_get_main_queue(); 22 | 23 | NSMutableArray *arr = [NSMutableArray new]; 24 | 25 | NSUInteger threads = [[NSProcessInfo processInfo] activeProcessorCount]; 26 | for (NSUInteger i = 0; i < threads; i++) { 27 | MoneroBackendCPUThread *th = [[MoneroBackendCPUThread alloc] init]; 28 | [th setBackend:self]; 29 | [th setName:[NSString stringWithFormat:@"MoneroCPUBackend %@/%@",@(i),@(threads)]]; 30 | [th setQualityOfService:NSQualityOfServiceUserInteractive]; 31 | [th start]; 32 | [arr addObject:th]; 33 | } 34 | 35 | #if TARGET_OS_OSX 36 | NSArray *metalDevices = MTLCopyAllDevices(); 37 | #else 38 | NSArray *metalDevices = [NSArray arrayWithObjects:MTLCreateSystemDefaultDevice(), nil]; 39 | #endif 40 | for (id device in metalDevices) { 41 | MoneroBackendMetalThread *th = [[MoneroBackendMetalThread alloc] init]; 42 | [th setBackend:self]; 43 | [th setDevice:device]; 44 | [th setName:[NSString stringWithFormat:@"MoneroMetalBackend %@", [device name]]]; 45 | [th setQualityOfService:NSQualityOfServiceUserInteractive]; 46 | [th start]; 47 | [arr addObject:th]; 48 | } 49 | 50 | self.threadPool = arr; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)dealloc { 56 | for (NSThread *th in _threadPool) { 57 | [th cancel]; 58 | } 59 | } 60 | 61 | - (void)setCPULimit:(double)cpuLimit { 62 | _cpuLimit = MIN(1, MAX(0, cpuLimit)); 63 | } 64 | 65 | - (void)setMetalLimit:(double)metalLimit { 66 | _metalLimit = MIN(1, MAX(0, metalLimit)); 67 | } 68 | 69 | - (void)setCurrentJob:(MoneroBackendJob *)job { 70 | uint32_t nonce = arc4random(); 71 | if (job.nicehash) nonce = (nonce & 0x00FFFFFF) | (job.nonce & 0xFF000000); 72 | atomic_store(&self->_nonce, nonce); 73 | _currentJob = job; 74 | } 75 | 76 | - (double)hashRate { 77 | double rate = 0; 78 | for (id th in _threadPool) { 79 | rate += [th hashRate]; 80 | } 81 | return rate; 82 | } 83 | 84 | - (void)handleResult:(const struct MoneroHash*)hash withNonce:(uint32_t)nonce forJob:(NSString*)jobId { 85 | if (![jobId isEqualToString:self.currentJob.jobId]) return; 86 | id delegate = [self delegate]; 87 | struct MoneroHash cphash; 88 | memcpy(&cphash, hash, sizeof(struct MoneroHash)); 89 | dispatch_async(self.delegateQueue, ^{ 90 | [delegate foundResult:&cphash withNonce:nonce forJobId:jobId]; 91 | }); 92 | } 93 | 94 | - (uint32_t)nextNonceBlock:(uint32_t)count { 95 | return atomic_fetch_add(&self->_nonce, count); 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/blake256.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers 30 | 31 | #ifndef _BLAKE256_H_ 32 | #define _BLAKE256_H_ 33 | 34 | #include 35 | 36 | typedef struct { 37 | uint32_t h[8], s[4], t[2]; 38 | int buflen, nullt; 39 | uint8_t buf[64]; 40 | } state; 41 | 42 | typedef struct { 43 | state inner; 44 | state outer; 45 | } hmac_state; 46 | 47 | void blake256_init(state *); 48 | void blake224_init(state *); 49 | 50 | void blake256_update(state *, const uint8_t *, uint64_t); 51 | void blake224_update(state *, const uint8_t *, uint64_t); 52 | 53 | void blake256_final(state *, uint8_t *); 54 | void blake224_final(state *, uint8_t *); 55 | 56 | void blake256_hash(uint8_t *, const uint8_t *, uint64_t); 57 | void blake224_hash(uint8_t *, const uint8_t *, uint64_t); 58 | 59 | /* HMAC functions: */ 60 | 61 | void hmac_blake256_init(hmac_state *, const uint8_t *, uint64_t); 62 | void hmac_blake224_init(hmac_state *, const uint8_t *, uint64_t); 63 | 64 | void hmac_blake256_update(hmac_state *, const uint8_t *, uint64_t); 65 | void hmac_blake224_update(hmac_state *, const uint8_t *, uint64_t); 66 | 67 | void hmac_blake256_final(hmac_state *, uint8_t *); 68 | void hmac_blake224_final(hmac_state *, uint8_t *); 69 | 70 | void hmac_blake256_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t); 71 | void hmac_blake224_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t); 72 | 73 | #endif /* _BLAKE256_H_ */ 74 | -------------------------------------------------------------------------------- /MoneroKit/Metal/stage2.metal: -------------------------------------------------------------------------------- 1 | // 2 | // stage2.metal 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 25.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #include "aes.metal" 13 | 14 | #include "MetalGranularity.h" 15 | 16 | constant static const constexpr size_t expandedKeySize = 320; 17 | constant static const constexpr size_t threadMemorySize = 1 << 21; 18 | constant static const constexpr size_t stateSize = 320; 19 | 20 | kernel void cn_stage2_0( 21 | device uint8_t *statebuf [[ buffer(0) ]], 22 | device uint8_t *ekeybuf [[ buffer(1) ]], 23 | device uint8_t *membuf [[ buffer(2) ]], 24 | uint2 idx [[ thread_position_in_grid ]] 25 | ) 26 | { 27 | device uint4 *state = (device uint4*)(statebuf + idx.x * stateSize) + 4 + idx.y; 28 | device uint4 *expandedKey = (device uint4*)(ekeybuf + idx.x * expandedKeySize); 29 | device uint4 *long_state = (device uint4*)(membuf + idx.x * threadMemorySize) + idx.y; 30 | 31 | thread uint4 ek[10] = { 32 | expandedKey[0], expandedKey[1], expandedKey[2], expandedKey[3], 33 | expandedKey[4], expandedKey[5], expandedKey[6], expandedKey[7], 34 | expandedKey[8], expandedKey[9] 35 | }; 36 | 37 | uint4 buf = state[0]; 38 | 39 | for (uint32_t i = 0; i < threadMemorySize / 128 / GRANULARITY; i++) { 40 | aes_round(buf, ek[0]); 41 | aes_round(buf, ek[1]); 42 | aes_round(buf, ek[2]); 43 | aes_round(buf, ek[3]); 44 | aes_round(buf, ek[4]); 45 | aes_round(buf, ek[5]); 46 | aes_round(buf, ek[6]); 47 | aes_round(buf, ek[7]); 48 | aes_round(buf, ek[8]); 49 | aes_round(buf, ek[9]); 50 | *long_state = buf; 51 | long_state += 8; 52 | } 53 | } 54 | 55 | kernel void cn_stage2_n( 56 | device uint8_t *ekeybuf [[ buffer(0) ]], 57 | device uint8_t *membuf [[ buffer(1) ]], 58 | device uint8_t *partbuf [[ buffer(2) ]], 59 | uint2 idx [[ thread_position_in_grid ]] 60 | ) 61 | { 62 | device uint4 *expandedKey = (device uint4*)(ekeybuf + idx.x * expandedKeySize); 63 | device uint4 *long_state = (device uint4*)(membuf + idx.x * threadMemorySize) + idx.y; 64 | uint32_t part = (uint32_t)(*partbuf); 65 | long_state += (threadMemorySize / 128 / GRANULARITY * part - 1) * 8; 66 | 67 | thread uint4 ek[10] = { 68 | expandedKey[0], expandedKey[1], expandedKey[2], expandedKey[3], 69 | expandedKey[4], expandedKey[5], expandedKey[6], expandedKey[7], 70 | expandedKey[8], expandedKey[9] 71 | }; 72 | 73 | uint4 buf = long_state[0]; 74 | 75 | for (uint32_t i = 0; i < threadMemorySize / 128 / GRANULARITY; i++) { 76 | aes_round(buf, ek[0]); 77 | aes_round(buf, ek[1]); 78 | aes_round(buf, ek[2]); 79 | aes_round(buf, ek[3]); 80 | aes_round(buf, ek[4]); 81 | aes_round(buf, ek[5]); 82 | aes_round(buf, ek[6]); 83 | aes_round(buf, ek[7]); 84 | aes_round(buf, ek[8]); 85 | aes_round(buf, ek[9]); 86 | long_state += 8; 87 | *long_state = buf; 88 | } 89 | } 90 | 91 | -------------------------------------------------------------------------------- /MoneroKit.xcodeproj/xcshareddata/xcschemes/MoneroKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /MoneroKitSample/iOS/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MoneroKitSample-iOS 4 | // 5 | // Created by Yury Popov on 10.01.2018. 6 | // 7 | 8 | @import UIKit; 9 | 10 | @import MoneroKit; 11 | 12 | @interface ViewController : UIViewController 13 | @property (atomic, strong) MoneroMiner *miner; 14 | @property (atomic, strong) NSTimer *hashrateTimer; 15 | @property (atomic, strong) NSDateFormatter *dateFormatter; 16 | 17 | @property (nonatomic, weak) IBOutlet UILabel *hashRateLabel; 18 | @property (nonatomic, weak) IBOutlet UILabel *difficultyLabel; 19 | @property (nonatomic, weak) IBOutlet UILabel *lastBlockLabel; 20 | @property (nonatomic, weak) IBOutlet UILabel *lastResultLabel; 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | 28 | self.dateFormatter = [NSDateFormatter new]; 29 | [self.dateFormatter setLocale:[NSLocale autoupdatingCurrentLocale]]; 30 | [self.dateFormatter setTimeZone:[NSTimeZone localTimeZone]]; 31 | [self.dateFormatter setDateStyle:NSDateFormatterShortStyle]; 32 | [self.dateFormatter setTimeStyle:NSDateFormatterShortStyle]; 33 | 34 | [self.lastBlockLabel setText:[self.dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:0]]]; 35 | 36 | MoneroWorker *worker = [MoneroWorker workerWithIdentifier:@"default" 37 | poolHost:@"moneropool.phoenix.dj" 38 | port:7777 39 | secure:NO 40 | nicehash:NO 41 | walletAddress:@"" 42 | password:@"x" 43 | weight:1]; 44 | 45 | self.miner = [MoneroMiner new]; 46 | [self.miner setWorkers:@[worker]]; 47 | [self.miner setCPULimit:1]; 48 | [self.miner setMetalLimit:1]; 49 | [self.miner setDelegate:self]; 50 | [self.miner startMining]; 51 | 52 | self.hashrateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(trackHashrate) userInfo:nil repeats:YES]; 53 | } 54 | 55 | - (void)acceptedResult:(NSUInteger)result forWorker:(nonnull NSString *)workerId { 56 | dispatch_async(dispatch_get_main_queue(), ^{ 57 | [self.lastResultLabel setText:[NSString stringWithFormat:@"%@", @(result)]]; 58 | }); 59 | } 60 | 61 | - (void)blockFoundForWorker:(nonnull NSString *)workerId { 62 | dispatch_async(dispatch_get_main_queue(), ^{ 63 | [self.lastBlockLabel setText:[self.dateFormatter stringFromDate:[NSDate new]]]; 64 | }); 65 | } 66 | 67 | - (void)difficultyChanged:(NSUInteger)difficulty forWorker:(nonnull NSString *)workerId { 68 | dispatch_async(dispatch_get_main_queue(), ^{ 69 | [self.difficultyLabel setText:[NSString stringWithFormat:@"%@", @(difficulty)]]; 70 | }); 71 | } 72 | 73 | - (void)miningError:(nonnull NSError *)error stopped:(BOOL)stopped { 74 | NSLog(@"Error%@: %@", stopped ? @" (mining stopped)" : @"", error); 75 | } 76 | 77 | - (void)trackHashrate { 78 | dispatch_async(dispatch_get_main_queue(), ^{ 79 | [self.hashRateLabel setText:[NSString stringWithFormat:@"%.01f H/s", self.miner.hashRate]]; 80 | }); 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MoneroKit 2 | _Monero mining on Apple devices_ 3 | 4 | [![release](https://img.shields.io/github/release/djphoenix/MoneroKit.svg)](https://github.com/djphoenix/MoneroKit/releases) [![issues](https://img.shields.io/github/issues/djphoenix/MoneroKit.svg)](https://github.com/djphoenix/MoneroKit/issues) [![pull requests](https://img.shields.io/github/issues-pr/djphoenix/MoneroKit.svg)](https://github.com/djphoenix/MoneroKit/pulls) [![license](https://img.shields.io/github/license/djphoenix/MoneroKit.svg)](https://github.com/djphoenix/MoneroKit/blob/master/LICENSE.md) 5 | 6 | ## Features 7 | - Powerful & well-optimized mining core 8 | - Multiple wallets/pools support - developer, vendor, end-user, etc 9 | - Multiple backends - CPU (with multi-threading auto-scaling) and Metal (Apple GPU) 10 | - Resource limits - leave something for regular device usage 11 | - Want more? Welcome to Issues section! 12 | 13 | ## Installation 14 | 15 | 1. Download source (or use [git submodules](https://git-scm.com/docs/git-submodule)) into your project 16 | 2. Add MoneroKit.xcodeproj as a sub-project or into your workspace 17 | 3. Add MoneroKit.framework into "Link Binary With Libraries" section of project "Build Phases" 18 | 4. In your project/view initialization, add miner initialization code and implement "MoneroMinerDelegate" protocol (look in MoneroKitSample directory for examples) 19 | 20 | ## Mining pools 21 | 22 | Some pools introduced limits for botnet/webmining workers. To avoid limits, you can (and should) use [xmr-node-proxy](https://github.com/Snipa22/xmr-node-proxy). 23 | 24 | ## Developer support 25 | 26 | You may define multiple workers in your project, and define "weight" for each worker. If you want to support further development of MoneroKit, you may use following worker configuration: 27 | 28 | ``` 29 | let developerWorker = MoneroWorker( 30 | identifier: "donation", 31 | poolHost: "moneropool.phoenix.dj", 32 | port: 7777, 33 | secure: false, 34 | walletAddress: "", 35 | password: "x", 36 | weight: 0.1 // 10% donation 37 | ) 38 | ``` 39 | 40 | Feel free to pick any weight for donation worker, and thank you for support! 41 | 42 | If you prefer one-time donation, you can use following Monero Wallet Address: 43 | 44 | `48xSeFyBQRmRv7BFbQU16wVEVsWrEEGEuMDHjP66roWXHCLvKesdsTxWS6ef9SdHzeQZW1Lxds9rYGwiqHhpoW393S7ZAPM` 45 | 46 | ## License 47 | 48 | © 2018 Yury Popov _a.k.a. PhoeniX_ 49 | 50 | 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: 51 | 52 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 53 | 54 | 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. 55 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/groestl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | #ifndef __hash_h 30 | #define __hash_h 31 | /* 32 | #include "crypto_uint8.h" 33 | #include "crypto_uint32.h" 34 | #include "crypto_uint64.h" 35 | #include "crypto_hash.h" 36 | 37 | typedef crypto_uint8 uint8_t; 38 | typedef crypto_uint32 uint32_t; 39 | typedef crypto_uint64 uint64_t; 40 | */ 41 | #include 42 | 43 | /* some sizes (number of bytes) */ 44 | #define ROWS 8 45 | #define LENGTHFIELDLEN ROWS 46 | #define COLS512 8 47 | 48 | #define SIZE512 (ROWS*COLS512) 49 | 50 | #define ROUNDS512 10 51 | #define HASH_BIT_LEN 256 52 | 53 | #define ROTL32(v, n) ((((v)<<(n))|((v)>>(32-(n))))&li_32(ffffffff)) 54 | 55 | 56 | #define li_32(h) 0x##h##u 57 | #define EXT_BYTE(var,n) ((uint8_t)((uint32_t)(var) >> (8*n))) 58 | #define u32BIG(a) \ 59 | ((ROTL32(a,8) & li_32(00FF00FF)) | \ 60 | (ROTL32(a,24) & li_32(FF00FF00))) 61 | 62 | 63 | /* NIST API begin */ 64 | typedef unsigned char BitSequence; 65 | typedef unsigned long long DataLength; 66 | typedef struct { 67 | uint32_t chaining[SIZE512/sizeof(uint32_t)]; /* actual state */ 68 | uint32_t block_counter1, 69 | block_counter2; /* message block counter(s) */ 70 | BitSequence buffer[SIZE512]; /* data buffer */ 71 | int buf_ptr; /* data buffer pointer */ 72 | int bits_in_last_byte; /* no. of message bits in last byte of 73 | data buffer */ 74 | } hashState; 75 | 76 | /*void Init(hashState*); 77 | void Update(hashState*, const BitSequence*, DataLength); 78 | void Final(hashState*, BitSequence*); */ 79 | void groestl(const BitSequence*, DataLength, BitSequence*); 80 | /* NIST API end */ 81 | 82 | /* 83 | int crypto_hash(unsigned char *out, 84 | const unsigned char *in, 85 | unsigned long long len); 86 | */ 87 | 88 | #endif /* __hash_h */ 89 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/keccak.c: -------------------------------------------------------------------------------- 1 | // keccak.c 2 | // 19-Nov-11 Markku-Juhani O. Saarinen 3 | // A baseline Keccak (3rd round) implementation. 4 | 5 | #include 6 | #include 7 | #include "hash-ops.h" 8 | #include "keccak.h" 9 | 10 | const uint64_t keccakf_rndc[24] = 11 | { 12 | 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 13 | 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 14 | 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 15 | 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 16 | 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 17 | 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 18 | 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 19 | 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 20 | }; 21 | 22 | const int keccakf_rotc[24] = 23 | { 24 | 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 25 | 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 26 | }; 27 | 28 | const int keccakf_piln[24] = 29 | { 30 | 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 31 | 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 32 | }; 33 | 34 | // update the state with given number of rounds 35 | 36 | void keccakf(uint64_t st[25], int rounds) 37 | { 38 | int i, j, round; 39 | uint64_t t, bc[5]; 40 | 41 | for (round = 0; round < rounds; round++) { 42 | 43 | // Theta 44 | for (i = 0; i < 5; i++) 45 | bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; 46 | 47 | for (i = 0; i < 5; i++) { 48 | t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); 49 | for (j = 0; j < 25; j += 5) 50 | st[j + i] ^= t; 51 | } 52 | 53 | // Rho Pi 54 | t = st[1]; 55 | for (i = 0; i < 24; i++) { 56 | j = keccakf_piln[i]; 57 | bc[0] = st[j]; 58 | st[j] = ROTL64(t, keccakf_rotc[i]); 59 | t = bc[0]; 60 | } 61 | 62 | // Chi 63 | for (j = 0; j < 25; j += 5) { 64 | for (i = 0; i < 5; i++) 65 | bc[i] = st[j + i]; 66 | for (i = 0; i < 5; i++) 67 | st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; 68 | } 69 | 70 | // Iota 71 | st[0] ^= keccakf_rndc[round]; 72 | } 73 | } 74 | 75 | // compute a keccak hash (md) of given byte length from "in" 76 | typedef uint64_t state_t[25]; 77 | 78 | void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen) 79 | { 80 | state_t st; 81 | uint8_t temp[144]; 82 | size_t i, rsiz, rsizw; 83 | 84 | if (mdlen <= 0 || mdlen > 200 || sizeof(st) != 200) 85 | { 86 | fprintf(stderr, "Bad keccak use"); 87 | abort(); 88 | } 89 | 90 | rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * (size_t)mdlen; 91 | rsizw = rsiz / 8; 92 | 93 | memset(st, 0, sizeof(st)); 94 | 95 | for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) { 96 | for (i = 0; i < rsizw; i++) 97 | st[i] ^= ((uint64_t *) in)[i]; 98 | keccakf(st, KECCAK_ROUNDS); 99 | } 100 | 101 | // last block and padding 102 | if (inlen >= sizeof(temp) || inlen > rsiz || rsiz - inlen + inlen + 1 >= sizeof(temp) || rsiz == 0 || rsiz - 1 >= sizeof(temp) || rsizw * 8 > sizeof(temp)) 103 | { 104 | fprintf(stderr, "Bad keccak use"); 105 | abort(); 106 | } 107 | 108 | memcpy(temp, in, inlen); 109 | temp[inlen++] = 1; 110 | memset(temp + inlen, 0, rsiz - inlen); 111 | temp[rsiz - 1] |= 0x80; 112 | 113 | for (i = 0; i < rsizw; i++) 114 | st[i] ^= ((uint64_t *) temp)[i]; 115 | 116 | keccakf(st, KECCAK_ROUNDS); 117 | 118 | memcpy(md, st, mdlen); 119 | } 120 | 121 | void keccak1600(const uint8_t *in, size_t inlen, uint8_t *md) 122 | { 123 | keccak(in, inlen, md, sizeof(state_t)); 124 | } 125 | -------------------------------------------------------------------------------- /MoneroKit/Metal/keccak.metal: -------------------------------------------------------------------------------- 1 | #define KECCAK_ROUNDS 24 2 | #define HASH_DATA_AREA 136 3 | #define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) 4 | 5 | #include "u64.metal" 6 | 7 | typedef _uint64_t state_t[25]; 8 | 9 | constant static const _uint64_t keccakf_rndc[24] = { 10 | 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 11 | 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 12 | 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 13 | 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 14 | 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 15 | 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 16 | 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 17 | 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 18 | }; 19 | 20 | constant static const uint32_t keccakf_rotc[24] = { 21 | 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 22 | 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 23 | }; 24 | 25 | constant static const uint32_t keccakf_piln[24] = { 26 | 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 27 | 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 28 | }; 29 | 30 | static inline __attribute__((always_inline)) void keccakf(volatile state_t &st, uint32_t rounds) { 31 | uint32_t i, j, r; 32 | _uint64_t t; 33 | _uint64_t __attribute__((aligned(16))) bc[5]; 34 | 35 | for (r = 0; r < rounds; r++) { 36 | for (i = 0; i < 5; i++) 37 | bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; 38 | for (i = 0; i < 5; i++) { 39 | t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); 40 | st[0 + i] ^= t; 41 | st[5 + i] ^= t; 42 | st[10 + i] ^= t; 43 | st[15 + i] ^= t; 44 | st[20 + i] ^= t; 45 | } 46 | t = st[1]; 47 | for (i = 0; i < 24; i++) { 48 | j = keccakf_piln[i]; 49 | bc[0] = st[j]; 50 | st[j] = ROTL64(t, keccakf_rotc[i]); 51 | t = bc[0]; 52 | } 53 | 54 | for (i = 0; i < 5; i++) 55 | bc[i] = st[0 + i]; 56 | for (i = 0; i < 5; i++) 57 | st[0 + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; 58 | 59 | for (i = 0; i < 5; i++) 60 | bc[i] = st[5 + i]; 61 | for (i = 0; i < 5; i++) 62 | st[5 + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; 63 | 64 | for (i = 0; i < 5; i++) 65 | bc[i] = st[10 + i]; 66 | for (i = 0; i < 5; i++) 67 | st[10 + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; 68 | 69 | for (i = 0; i < 5; i++) 70 | bc[i] = st[15 + i]; 71 | for (i = 0; i < 5; i++) 72 | st[15 + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; 73 | 74 | for (i = 0; i < 5; i++) 75 | bc[i] = st[20 + i]; 76 | for (i = 0; i < 5; i++) 77 | st[20 + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; 78 | 79 | st[0] ^= keccakf_rndc[r]; 80 | } 81 | } 82 | 83 | static inline __attribute__((always_inline)) void keccak(const device uint8_t *in, size_t inlen, device uint8_t *md, size_t mdlen) { 84 | state_t __attribute__((aligned(16))) st; 85 | uint8_t temp[144]; 86 | size_t i, rsiz, rsizw, inoff = 0; 87 | 88 | rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; 89 | rsizw = rsiz / 8; 90 | 91 | for (i = 0; i < sizeof(st) / 8; i++) st[i] = 0; 92 | 93 | for ( ; inlen >= rsiz; inlen -= rsiz, inoff += rsiz) { 94 | for (i = 0; i < rsizw; i++) st[i] ^= ((const device _uint64_t*)(in + inoff))[i]; 95 | keccakf(st, KECCAK_ROUNDS); 96 | } 97 | 98 | for (i = 0; i < inlen; i++) ((thread uint8_t*)temp)[i] = ((const device uint8_t*)(in + inoff))[i]; 99 | inoff += inlen; 100 | temp[inlen++] = 1; 101 | for (i = 0; i < rsiz - inlen; i++) ((thread uint8_t*)temp)[inlen + i] = 0; 102 | temp[rsiz - 1] |= 0x80; 103 | for (i = 0; i < rsizw; i++) st[i] ^= ((const thread _uint64_t*)temp)[i]; 104 | keccakf(st, KECCAK_ROUNDS); 105 | 106 | for (i = 0; i < mdlen; i++) md[i] = ((const thread uint8_t*)st)[i]; 107 | } 108 | 109 | static inline __attribute__((always_inline)) void keccak1600(const device uint8_t *in, size_t inlen, device uint8_t *md) { 110 | keccak(in, inlen, md, sizeof(state_t)); 111 | } 112 | -------------------------------------------------------------------------------- /MoneroKit/Metal/aes.metal: -------------------------------------------------------------------------------- 1 | constant static const uint8_t aes_gf_8[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; 2 | constant static const uint8_t aes_sub_byte_value[] = { 3 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 4 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 5 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 6 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 7 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 8 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 9 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 10 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 11 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 12 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 13 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 14 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 15 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 16 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 17 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 18 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, 19 | }; 20 | 21 | static inline __attribute__((always_inline)) void aes_expand_key(device uint8_t *expandedKey, device uint8_t *data) { 22 | device uchar4 *key = (device uchar4*)expandedKey; 23 | uint8_t i, x = 0; 24 | __attribute__((aligned(4))) uchar4 temp; 25 | 26 | ((device uint4*)expandedKey)[0] = ((device uint4*)data)[0]; 27 | ((device uint4*)expandedKey)[1] = ((device uint4*)data)[1]; 28 | for (i = 8; i < 10*4; i++) { 29 | temp = key[i-1]; 30 | if (0 == i % 8) { 31 | temp = uchar4(temp[1], temp[2], temp[3], temp[0]); 32 | temp[0] = aes_sub_byte_value[temp[0]] ^ aes_gf_8[x++]; 33 | temp[1] = aes_sub_byte_value[temp[1]]; 34 | temp[2] = aes_sub_byte_value[temp[2]]; 35 | temp[3] = aes_sub_byte_value[temp[3]]; 36 | } else if (4 == i % 8) { 37 | temp[0] = aes_sub_byte_value[temp[0]]; 38 | temp[1] = aes_sub_byte_value[temp[1]]; 39 | temp[2] = aes_sub_byte_value[temp[2]]; 40 | temp[3] = aes_sub_byte_value[temp[3]]; 41 | } 42 | key[i] = key[i-8] ^ temp; 43 | } 44 | } 45 | 46 | static inline __attribute__((always_inline)) uchar4 transform_row(uchar4 row) { 47 | uchar4 t1 = uchar4(row[0] ^ row[1] ^ row[2] ^ row[3]); 48 | uchar4 t2 = row ^ uchar4(row[1], row[2], row[3], row[0]); 49 | uchar4 t3 = (t2 << 1) ^ ((t2 >> 7) * 0x1b); 50 | return t1 ^ t3; 51 | } 52 | 53 | static inline __attribute__((always_inline)) void aes_round(thread uint4 &out, const uint4 key) { 54 | thread uchar4 *bout = (thread uchar4*)&out; 55 | uint8_t t; 56 | 57 | bout[0][0] = aes_sub_byte_value[bout[0][0]]; 58 | bout[1][0] = aes_sub_byte_value[bout[1][0]]; 59 | bout[2][0] = aes_sub_byte_value[bout[2][0]]; 60 | bout[3][0] = aes_sub_byte_value[bout[3][0]]; 61 | 62 | t = aes_sub_byte_value[bout[0][1]]; 63 | bout[0][1] = aes_sub_byte_value[bout[1][1]]; 64 | bout[1][1] = aes_sub_byte_value[bout[2][1]]; 65 | bout[2][1] = aes_sub_byte_value[bout[3][1]]; 66 | bout[3][1] = t; 67 | 68 | t = aes_sub_byte_value[bout[0][2]]; 69 | bout[0][2] = aes_sub_byte_value[bout[2][2]]; 70 | bout[2][2] = t; 71 | 72 | t = aes_sub_byte_value[bout[1][2]]; 73 | bout[1][2] = aes_sub_byte_value[bout[3][2]]; 74 | bout[3][2] = t; 75 | 76 | t = aes_sub_byte_value[bout[0][3]]; 77 | bout[0][3] = aes_sub_byte_value[bout[3][3]]; 78 | bout[3][3] = aes_sub_byte_value[bout[2][3]]; 79 | bout[2][3] = aes_sub_byte_value[bout[1][3]]; 80 | bout[1][3] = t; 81 | 82 | __attribute__((aligned(16))) uchar4 tmp[4] = { 83 | transform_row(bout[0]), 84 | transform_row(bout[1]), 85 | transform_row(bout[2]), 86 | transform_row(bout[3]) 87 | }; 88 | out ^= *(thread uint4*)tmp ^ key; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /MoneroKit/Metal/stage3_2.metal: -------------------------------------------------------------------------------- 1 | // 2 | // stage3.metal 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 25.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #include "u64.metal" 13 | #include "aes.metal" 14 | #include "mul128.metal" 15 | 16 | constant static const constexpr size_t threadMemorySize = 1 << 21; 17 | constant static const constexpr size_t stateSize = 320; 18 | constant static const constexpr size_t ITER = (1 << 20); 19 | 20 | #include "MetalGranularity.h" 21 | 22 | static inline __attribute__((always_inline)) void cn_v2_shuffle_add(device uint8_t *hp_state, const thread uint32_t j, const thread uint4 _a, const thread uint4 _b, const thread uint4 _b1) { 23 | const uint4 chunk1 = *(device uint4*)(hp_state + (j ^ 0x10)); 24 | const uint4 chunk2 = *(device uint4*)(hp_state + (j ^ 0x20)); 25 | const uint4 chunk3 = *(device uint4*)(hp_state + (j ^ 0x30)); 26 | ((thread _uint64_t*)&chunk1)[0] += ((thread _uint64_t*)&_b)[0]; 27 | ((thread _uint64_t*)&chunk1)[1] += ((thread _uint64_t*)&_b)[1]; 28 | ((thread _uint64_t*)&chunk2)[0] += ((thread _uint64_t*)&_a)[0]; 29 | ((thread _uint64_t*)&chunk2)[1] += ((thread _uint64_t*)&_a)[1]; 30 | ((thread _uint64_t*)&chunk3)[0] += ((thread _uint64_t*)&_b1)[0]; 31 | ((thread _uint64_t*)&chunk3)[1] += ((thread _uint64_t*)&_b1)[1]; 32 | *(device uint4*)(hp_state + (j ^ 0x10)) = chunk3; 33 | *(device uint4*)(hp_state + (j ^ 0x20)) = chunk1; 34 | *(device uint4*)(hp_state + (j ^ 0x30)) = chunk2; 35 | } 36 | 37 | kernel void cn_stage3_n_v2( 38 | device uint8_t *statebuf [[ buffer(0) ]], 39 | device uint8_t *membuf [[ buffer(1) ]], 40 | uint idx [[ thread_position_in_grid ]] 41 | ) 42 | { 43 | device uint8_t *state = (statebuf + idx * stateSize); 44 | device uint8_t *long_state = (membuf + idx * threadMemorySize); 45 | device uint4 *_a = (device uint4*)(state + 208); 46 | device uint4 *_b = (device uint4*)(state + 224); 47 | device uint4 *_b1 = (device uint4*)(state + 240); 48 | device uint2 *_division_result = (device uint2*)(state + 256); 49 | device uint2 *_sqrt_result = (device uint2*)(state + 264); 50 | device uint4 *p; 51 | 52 | thread uint4 a = *_a, b = *_b, b1 = *_b1, c, c1, t; 53 | thread _uint64_t division_result = *(device _uint64_t*)_division_result; 54 | thread _uint64_t sqrt_result = *(device _uint64_t*)_sqrt_result; 55 | thread uint32_t j; 56 | 57 | for(size_t i = 0; i < ITER / 2 / GRANULARITY; i++) { 58 | // Iteration 1 59 | j = a.x & 0x1ffff0; 60 | p = (device uint4*)&long_state[j]; 61 | c = *p; 62 | aes_round(c, a); 63 | cn_v2_shuffle_add(long_state, j, a, b, b1); 64 | *p = b ^ c; 65 | 66 | // Iteration 2 67 | j = c.x & 0x1ffff0; 68 | p = (device uint4*)&long_state[j]; 69 | c1 = *p; 70 | { 71 | ((thread _uint64_t*)(&c1))[0] ^= division_result ^ (sqrt_result << 32); 72 | const _uint64_t dividend = ((thread _uint64_t*)(&c))[1]; 73 | const uint32_t divisor = (uint32_t)(((thread _uint64_t*)(&c))[0] + (uint32_t)(sqrt_result << 1)) | 0x80000001UL; 74 | division_result = ((uint32_t)(dividend / divisor)) + (((_uint64_t)(dividend % divisor)) << 32); 75 | _uint64_t sqrt_input = ((thread _uint64_t*)(&c))[0] + (_uint64_t)division_result; 76 | 77 | _uint64_t r = 1ULL << 63; 78 | for (_uint64_t bit = 1ULL << 60; bit; bit >>= 2) { 79 | if (sqrt_input < r + bit) { 80 | r = r >> 1; 81 | } else { 82 | sqrt_input = (sqrt_input - (r + bit)); 83 | r = (r + bit * 2) >> 1; 84 | } 85 | } 86 | sqrt_result = (uint32_t)(r * 2 + ((sqrt_input > r) ? 1 : 0)); 87 | } 88 | mul128(*(thread uint2*)&c, *(thread uint2*)&c1, t); 89 | { 90 | *(device uint4*)(long_state + (j ^ 0x10)) ^= *((const thread uint4*)&t); 91 | *(thread uint4*)&t ^= *(const device uint4*)(long_state + (j ^ 0x20)); 92 | } 93 | cn_v2_shuffle_add(long_state, j, a, b, b1); 94 | ((thread _uint64_t*)&a)[0] += ((const thread _uint64_t*)&t)[0]; 95 | ((thread _uint64_t*)&a)[1] += ((const thread _uint64_t*)&t)[1]; 96 | *p = a; 97 | a ^= c1; 98 | b1 = b; 99 | b = c; 100 | } 101 | 102 | *_a = a; *_b = b; *_b1 = b1; 103 | *(device _uint64_t*)_division_result = division_result; 104 | *(device _uint64_t*)_sqrt_result = sqrt_result; 105 | } 106 | -------------------------------------------------------------------------------- /MoneroKit/MoneroWorker.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroWorker.m 3 | // MoneroMiner 4 | // 5 | // Created by Yury Popov on 27.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroKit.h" 10 | 11 | @implementation MoneroWorker 12 | 13 | + (instancetype)workerWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString *)wallet { 14 | return [self workerWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:NO walletAddress:wallet password:@"x" weight:1]; 15 | } 16 | 17 | + (instancetype)workerWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString *)wallet password:(NSString *)password { 18 | return [self workerWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:NO walletAddress:wallet password:password weight:1]; 19 | } 20 | 21 | + (instancetype)workerWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString *)wallet password:(NSString *)password weight:(double)weight { 22 | return [self workerWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:NO walletAddress:wallet password:password weight:weight]; 23 | } 24 | 25 | + (instancetype)workerWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString *)wallet { 26 | return [self workerWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:nicehash walletAddress:wallet password:@"x" weight:1]; 27 | } 28 | 29 | + (instancetype)workerWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString *)wallet password:(NSString *)password { 30 | return [self workerWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:nicehash walletAddress:wallet password:password weight:1]; 31 | } 32 | 33 | + (instancetype)workerWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString *)wallet password:(NSString *)password weight:(double)weight { 34 | return [[self alloc] initWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:nicehash walletAddress:wallet password:password weight:weight]; 35 | } 36 | 37 | - (instancetype)initWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString *)wallet { 38 | return [self initWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:NO walletAddress:wallet password:@"x" weight:1]; 39 | } 40 | 41 | - (instancetype)initWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString *)wallet password:(NSString *)password { 42 | return [self initWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:NO walletAddress:wallet password:password weight:1]; 43 | } 44 | 45 | - (instancetype)initWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString *)wallet password:(NSString *)password weight:(double)weight { 46 | return [self initWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:NO walletAddress:wallet password:password weight:1]; 47 | } 48 | 49 | - (instancetype)initWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString *)wallet { 50 | return [self initWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:nicehash walletAddress:wallet password:@"x" weight:1]; 51 | } 52 | 53 | - (instancetype)initWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString *)wallet password:(NSString *)password { 54 | return [self initWithIdentifier:identifier poolHost:host port:port secure:secure nicehash:nicehash walletAddress:wallet password:password weight:1]; 55 | } 56 | 57 | - (instancetype)initWithIdentifier:(NSString *)identifier poolHost:(NSString *)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString *)wallet password:(NSString *)password weight:(double)weight { 58 | if (self = [super init]) { 59 | _identifier = [identifier copy]; 60 | _poolHost = [host copy]; 61 | _poolPort = port; 62 | _poolSecure = secure; 63 | _nicehash = nicehash; 64 | _walletAddress = [wallet copy]; 65 | _password = [password copy]; 66 | _weight = weight; 67 | } 68 | return self; 69 | } 70 | 71 | - (NSString *)description { 72 | return [NSString stringWithFormat:@"<%@:%@ stratum+%@://[%@:%@]@%@:%@ nicehash:%@ weight:%@>", NSStringFromClass([self class]), _identifier, _poolSecure ? @"ssl" : @"tcp", _walletAddress, _password, _poolHost, @(_poolPort), _nicehash ? @"YES" : @"NO", @(_weight)]; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /MoneroKit/CPU/MoneroBackendCPUThread.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroCPUBackend.m 3 | // MoneroKit 4 | // 5 | // Created by Yury Popov on 10.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroBackendCPUThread.h" 10 | 11 | #import 12 | #import 13 | #import "MoneroBackend_private.h" 14 | #import "hash-ops.h" 15 | 16 | @implementation MoneroBackendCPUThread { 17 | _Atomic(double) hashrate; 18 | _Atomic(uint32_t) ratecount; 19 | } 20 | 21 | #if defined DEBUG && DEBUG 22 | static void performTests() { 23 | __attribute__((aligned(16))) struct MoneroHash hash; 24 | void *hashbuf = cn_slow_hash_alloc(); 25 | 26 | cn_slow_hash((const uint8_t[]){0x64, 0x65, 0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x62, 0x75, 0x73, 0x20, 0x64, 0x75, 0x62, 0x69, 0x74, 0x61, 0x6e, 0x64, 0x75, 0x6d}, 21, (char*)hash.bytes, hashbuf, 0, 0); 27 | if (memcmp(hash.bytes, (const uint8_t[]){ 0x2f, 0x8e, 0x3d, 0xf4, 0x0b, 0xd1, 0x1f, 0x9a, 0xc9, 0x0c, 0x74, 0x3c, 0xa8, 0xe3, 0x2b, 0xb3, 0x91, 0xda, 0x4f, 0xb9, 0x86, 0x12, 0xaa, 0x3b, 0x6c, 0xdc, 0x63, 0x9e, 0xe0, 0x0b, 0x31, 0xf5 }, 32) == 0) { 28 | NSLog(@"CPU: V0 passed"); 29 | } else { 30 | NSLog(@"CPU: V0 failed"); 31 | } 32 | 33 | cn_slow_hash((const uint8_t[]){0x37, 0xa6, 0x36, 0xd7, 0xda, 0xfd, 0xf2, 0x59, 0xb7, 0x28, 0x7e, 0xdd, 0xca, 0x2f, 0x58, 0x09, 0x9e, 0x98, 0x61, 0x9d, 0x2f, 0x99, 0xbd, 0xb8, 0x96, 0x9d, 0x7b, 0x14, 0x49, 0x81, 0x02, 0xcc, 0x06, 0x52, 0x01, 0xc8, 0xbe, 0x90, 0xbd, 0x77, 0x73, 0x23, 0xf4, 0x49, 0x84, 0x8b, 0x21, 0x5d, 0x29, 0x77, 0xc9, 0x2c, 0x4c, 0x1c, 0x2d, 0xa3, 0x6a, 0xb4, 0x6b, 0x2e, 0x38, 0x96, 0x89, 0xed, 0x97, 0xc1, 0x8f, 0xec, 0x08, 0xcd, 0x3b, 0x03, 0x23, 0x5c, 0x5e, 0x4c, 0x62, 0xa3, 0x7a, 0xd8, 0x8c, 0x7b, 0x67, 0x93, 0x24, 0x95, 0xa7, 0x10, 0x90, 0xe8, 0x5d, 0xd4, 0x02, 0x0a, 0x93, 0x00}, 96, (char*)hash.bytes, hashbuf, 1, 0); 34 | if (memcmp(hash.bytes, (const uint8_t[]){ 0x61, 0x3e, 0x63, 0x85, 0x05, 0xba, 0x1f, 0xd0, 0x5f, 0x42, 0x8d, 0x5c, 0x9f, 0x8e, 0x08, 0xf8, 0x16, 0x56, 0x14, 0x34, 0x2d, 0xac, 0x41, 0x9a, 0xdc, 0x6a, 0x47, 0xdc, 0xe2, 0x57, 0xeb, 0x3e }, 32) == 0) { 35 | NSLog(@"CPU: V1 passed"); 36 | } else { 37 | NSLog(@"CPU: V1 failed"); 38 | } 39 | 40 | cn_slow_hash((const uint8_t[]){0x69, 0x72, 0x75, 0x72, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74}, 47, (char*)hash.bytes, hashbuf, 2, 0); 41 | if (memcmp(hash.bytes, (const uint8_t[]){ 0x42, 0x2f, 0x8c, 0xfe, 0x80, 0x60, 0xcf, 0x6c, 0x3d, 0x9f, 0xd6, 0x6f, 0x68, 0xe3, 0xc9, 0x97, 0x7a, 0xdb, 0x68, 0x3a, 0xea, 0x27, 0x88, 0x02, 0x93, 0x08, 0xbb, 0xe9, 0xbc, 0x50, 0xd7, 0x28 }, 32) == 0) { 42 | NSLog(@"CPU: V2 passed"); 43 | } else { 44 | NSLog(@"CPU: V2 failed"); 45 | } 46 | 47 | cn_slow_hash((const uint8_t[]){0x73, 0x75, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x75, 0x6c, 0x70, 0x61, 0x20, 0x71, 0x75, 0x69, 0x20, 0x6f, 0x66, 0x66, 0x69, 0x63, 0x69, 0x61, 0x20, 0x64, 0x65, 0x73, 0x65, 0x72, 0x75, 0x6e, 0x74, 0x20, 0x6d, 0x6f, 0x6c, 0x6c, 0x69, 0x74, 0x20, 0x61, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x64, 0x20, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x75, 0x6d, 0x2e}, 62, (char*)hash.bytes, hashbuf, 4, 1806269); 48 | if (memcmp(hash.bytes, (const uint8_t[]){ 0x75, 0xc6, 0xf2, 0xae, 0x49, 0xa2, 0x05, 0x21, 0xde, 0x97, 0x28, 0x5b, 0x43, 0x1e, 0x71, 0x71, 0x25, 0x84, 0x7f, 0xb8, 0x93, 0x5e, 0xd8, 0x4a, 0x61, 0xe7, 0xf8, 0xd3, 0x6a, 0x2c, 0x3d, 0x8e }, 32) == 0) { 49 | NSLog(@"CPU: V4 passed"); 50 | } else { 51 | NSLog(@"CPU: V4 failed"); 52 | } 53 | 54 | free(hashbuf); 55 | } 56 | 57 | + (void)load { 58 | performTests(); 59 | } 60 | #endif 61 | 62 | - (void)main { 63 | __attribute__((aligned(16))) uint8_t blob_buffer[128]; 64 | __attribute__((aligned(16))) struct MoneroHash hash; 65 | uint32_t *nonce_ptr; 66 | uint32_t blob_len; 67 | uint32_t nonce; 68 | uint64_t target; 69 | MoneroBackendJob *job; 70 | double limit; 71 | struct timeval starttime, endtime; 72 | useconds_t worktime, sleeptime; 73 | uint64_t version, height; 74 | 75 | void *hashbuf = cn_slow_hash_alloc(); 76 | 77 | while (![self isCancelled]) { 78 | job = [self job]; 79 | if (job == nil) { 80 | atomic_store(&hashrate, 0); 81 | atomic_store(&ratecount, 0); 82 | [NSThread sleepForTimeInterval:0.01]; 83 | continue; 84 | } 85 | 86 | blob_len = (uint32_t)job.blob.length; 87 | [job.blob getBytes:blob_buffer length:sizeof(blob_buffer)]; 88 | nonce_ptr = (uint32_t*)(blob_buffer + job.nonceOffset); 89 | target = job.target; 90 | version = job.versionMajor > 6 ? job.versionMajor - 6 : 0; 91 | height = job.height; 92 | while (![self isCancelled]) { 93 | if (job != self.job) break; 94 | limit = self.resourceLimit; 95 | if (limit <= 0) { 96 | atomic_store(&hashrate, 0); 97 | atomic_store(&ratecount, 0); 98 | [NSThread sleepForTimeInterval:0.05]; 99 | continue; 100 | } 101 | gettimeofday(&starttime, nil); 102 | nonce = [self nonce]; 103 | memmove(nonce_ptr, &nonce, sizeof(nonce)); 104 | cn_slow_hash(blob_buffer, blob_len, (char*)hash.bytes, hashbuf, version, height); 105 | gettimeofday(&endtime, nil); 106 | if (hash.lluints[3] < target) { 107 | [self handleResult:&hash withNonce:nonce forJob:job.jobId]; 108 | } 109 | worktime = (useconds_t)(endtime.tv_sec - starttime.tv_sec) * 1000000 + (useconds_t)(endtime.tv_usec - starttime.tv_usec); 110 | { 111 | uint32_t cnt = MIN((uint32_t)atomic_fetch_add(&ratecount, 1), (uint32_t)10); 112 | double prevrate = atomic_load(&hashrate); 113 | atomic_store(&hashrate, ((((double)1000000 * limit) / (double)worktime) + (prevrate * (double)cnt)) / (double)(cnt + 1)); 114 | } 115 | if (limit < 1) { 116 | sleeptime = (useconds_t)((double)worktime * (1 - limit)); 117 | usleep(sleeptime); 118 | } 119 | } 120 | } 121 | free(hashbuf); 122 | } 123 | 124 | - (double)hashRate { 125 | return atomic_load(&hashrate); 126 | } 127 | 128 | - (uint32_t)nonce { 129 | __strong MoneroBackend *backend = [self backend]; 130 | if (!backend) return 0; 131 | return [backend nextNonceBlock:1]; 132 | } 133 | 134 | - (double)resourceLimit { 135 | __strong MoneroBackend *backend = [self backend]; 136 | if (!backend) return 0; 137 | return [backend cpuLimit]; 138 | } 139 | 140 | - (MoneroBackendJob*)job { 141 | __strong MoneroBackend *backend = [self backend]; 142 | if (!backend) return nil; 143 | return [backend currentJob]; 144 | } 145 | 146 | - (void)handleResult:(const struct MoneroHash*)hash withNonce:(uint32_t)nonce forJob:(NSString*)jobId { 147 | __strong MoneroBackend *backend = [self backend]; 148 | [backend handleResult:hash withNonce:nonce forJob:jobId]; 149 | } 150 | 151 | @end 152 | 153 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/groestl_tables.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | #ifndef __tables_h 30 | #define __tables_h 31 | 32 | 33 | const uint32_t T[512] = {0xa5f432c6, 0xc6a597f4, 0x84976ff8, 0xf884eb97, 0x99b05eee, 0xee99c7b0, 0x8d8c7af6, 0xf68df78c, 0xd17e8ff, 0xff0de517, 0xbddc0ad6, 0xd6bdb7dc, 0xb1c816de, 0xdeb1a7c8, 0x54fc6d91, 0x915439fc 34 | , 0x50f09060, 0x6050c0f0, 0x3050702, 0x2030405, 0xa9e02ece, 0xcea987e0, 0x7d87d156, 0x567dac87, 0x192bcce7, 0xe719d52b, 0x62a613b5, 0xb56271a6, 0xe6317c4d, 0x4de69a31, 0x9ab559ec, 0xec9ac3b5 35 | , 0x45cf408f, 0x8f4505cf, 0x9dbca31f, 0x1f9d3ebc, 0x40c04989, 0x894009c0, 0x879268fa, 0xfa87ef92, 0x153fd0ef, 0xef15c53f, 0xeb2694b2, 0xb2eb7f26, 0xc940ce8e, 0x8ec90740, 0xb1de6fb, 0xfb0bed1d 36 | , 0xec2f6e41, 0x41ec822f, 0x67a91ab3, 0xb3677da9, 0xfd1c435f, 0x5ffdbe1c, 0xea256045, 0x45ea8a25, 0xbfdaf923, 0x23bf46da, 0xf7025153, 0x53f7a602, 0x96a145e4, 0xe496d3a1, 0x5bed769b, 0x9b5b2ded 37 | , 0xc25d2875, 0x75c2ea5d, 0x1c24c5e1, 0xe11cd924, 0xaee9d43d, 0x3dae7ae9, 0x6abef24c, 0x4c6a98be, 0x5aee826c, 0x6c5ad8ee, 0x41c3bd7e, 0x7e41fcc3, 0x206f3f5, 0xf502f106, 0x4fd15283, 0x834f1dd1 38 | , 0x5ce48c68, 0x685cd0e4, 0xf4075651, 0x51f4a207, 0x345c8dd1, 0xd134b95c, 0x818e1f9, 0xf908e918, 0x93ae4ce2, 0xe293dfae, 0x73953eab, 0xab734d95, 0x53f59762, 0x6253c4f5, 0x3f416b2a, 0x2a3f5441 39 | , 0xc141c08, 0x80c1014, 0x52f66395, 0x955231f6, 0x65afe946, 0x46658caf, 0x5ee27f9d, 0x9d5e21e2, 0x28784830, 0x30286078, 0xa1f8cf37, 0x37a16ef8, 0xf111b0a, 0xa0f1411, 0xb5c4eb2f, 0x2fb55ec4 40 | , 0x91b150e, 0xe091c1b, 0x365a7e24, 0x2436485a, 0x9bb6ad1b, 0x1b9b36b6, 0x3d4798df, 0xdf3da547, 0x266aa7cd, 0xcd26816a, 0x69bbf54e, 0x4e699cbb, 0xcd4c337f, 0x7fcdfe4c, 0x9fba50ea, 0xea9fcfba 41 | , 0x1b2d3f12, 0x121b242d, 0x9eb9a41d, 0x1d9e3ab9, 0x749cc458, 0x5874b09c, 0x2e724634, 0x342e6872, 0x2d774136, 0x362d6c77, 0xb2cd11dc, 0xdcb2a3cd, 0xee299db4, 0xb4ee7329, 0xfb164d5b, 0x5bfbb616 42 | , 0xf601a5a4, 0xa4f65301, 0x4dd7a176, 0x764decd7, 0x61a314b7, 0xb76175a3, 0xce49347d, 0x7dcefa49, 0x7b8ddf52, 0x527ba48d, 0x3e429fdd, 0xdd3ea142, 0x7193cd5e, 0x5e71bc93, 0x97a2b113, 0x139726a2 43 | , 0xf504a2a6, 0xa6f55704, 0x68b801b9, 0xb96869b8, 0x0, 0x0, 0x2c74b5c1, 0xc12c9974, 0x60a0e040, 0x406080a0, 0x1f21c2e3, 0xe31fdd21, 0xc8433a79, 0x79c8f243, 0xed2c9ab6, 0xb6ed772c 44 | , 0xbed90dd4, 0xd4beb3d9, 0x46ca478d, 0x8d4601ca, 0xd9701767, 0x67d9ce70, 0x4bddaf72, 0x724be4dd, 0xde79ed94, 0x94de3379, 0xd467ff98, 0x98d42b67, 0xe82393b0, 0xb0e87b23, 0x4ade5b85, 0x854a11de 45 | , 0x6bbd06bb, 0xbb6b6dbd, 0x2a7ebbc5, 0xc52a917e, 0xe5347b4f, 0x4fe59e34, 0x163ad7ed, 0xed16c13a, 0xc554d286, 0x86c51754, 0xd762f89a, 0x9ad72f62, 0x55ff9966, 0x6655ccff, 0x94a7b611, 0x119422a7 46 | , 0xcf4ac08a, 0x8acf0f4a, 0x1030d9e9, 0xe910c930, 0x60a0e04, 0x406080a, 0x819866fe, 0xfe81e798, 0xf00baba0, 0xa0f05b0b, 0x44ccb478, 0x7844f0cc, 0xbad5f025, 0x25ba4ad5, 0xe33e754b, 0x4be3963e 47 | , 0xf30eaca2, 0xa2f35f0e, 0xfe19445d, 0x5dfeba19, 0xc05bdb80, 0x80c01b5b, 0x8a858005, 0x58a0a85, 0xadecd33f, 0x3fad7eec, 0xbcdffe21, 0x21bc42df, 0x48d8a870, 0x7048e0d8, 0x40cfdf1, 0xf104f90c 48 | , 0xdf7a1963, 0x63dfc67a, 0xc1582f77, 0x77c1ee58, 0x759f30af, 0xaf75459f, 0x63a5e742, 0x426384a5, 0x30507020, 0x20304050, 0x1a2ecbe5, 0xe51ad12e, 0xe12effd, 0xfd0ee112, 0x6db708bf, 0xbf6d65b7 49 | , 0x4cd45581, 0x814c19d4, 0x143c2418, 0x1814303c, 0x355f7926, 0x26354c5f, 0x2f71b2c3, 0xc32f9d71, 0xe13886be, 0xbee16738, 0xa2fdc835, 0x35a26afd, 0xcc4fc788, 0x88cc0b4f, 0x394b652e, 0x2e395c4b 50 | , 0x57f96a93, 0x93573df9, 0xf20d5855, 0x55f2aa0d, 0x829d61fc, 0xfc82e39d, 0x47c9b37a, 0x7a47f4c9, 0xacef27c8, 0xc8ac8bef, 0xe73288ba, 0xbae76f32, 0x2b7d4f32, 0x322b647d, 0x95a442e6, 0xe695d7a4 51 | , 0xa0fb3bc0, 0xc0a09bfb, 0x98b3aa19, 0x199832b3, 0xd168f69e, 0x9ed12768, 0x7f8122a3, 0xa37f5d81, 0x66aaee44, 0x446688aa, 0x7e82d654, 0x547ea882, 0xabe6dd3b, 0x3bab76e6, 0x839e950b, 0xb83169e 52 | , 0xca45c98c, 0x8cca0345, 0x297bbcc7, 0xc729957b, 0xd36e056b, 0x6bd3d66e, 0x3c446c28, 0x283c5044, 0x798b2ca7, 0xa779558b, 0xe23d81bc, 0xbce2633d, 0x1d273116, 0x161d2c27, 0x769a37ad, 0xad76419a 53 | , 0x3b4d96db, 0xdb3bad4d, 0x56fa9e64, 0x6456c8fa, 0x4ed2a674, 0x744ee8d2, 0x1e223614, 0x141e2822, 0xdb76e492, 0x92db3f76, 0xa1e120c, 0xc0a181e, 0x6cb4fc48, 0x486c90b4, 0xe4378fb8, 0xb8e46b37 54 | , 0x5de7789f, 0x9f5d25e7, 0x6eb20fbd, 0xbd6e61b2, 0xef2a6943, 0x43ef862a, 0xa6f135c4, 0xc4a693f1, 0xa8e3da39, 0x39a872e3, 0xa4f7c631, 0x31a462f7, 0x37598ad3, 0xd337bd59, 0x8b8674f2, 0xf28bff86 55 | , 0x325683d5, 0xd532b156, 0x43c54e8b, 0x8b430dc5, 0x59eb856e, 0x6e59dceb, 0xb7c218da, 0xdab7afc2, 0x8c8f8e01, 0x18c028f, 0x64ac1db1, 0xb16479ac, 0xd26df19c, 0x9cd2236d, 0xe03b7249, 0x49e0923b 56 | , 0xb4c71fd8, 0xd8b4abc7, 0xfa15b9ac, 0xacfa4315, 0x709faf3, 0xf307fd09, 0x256fa0cf, 0xcf25856f, 0xafea20ca, 0xcaaf8fea, 0x8e897df4, 0xf48ef389, 0xe9206747, 0x47e98e20, 0x18283810, 0x10182028 57 | , 0xd5640b6f, 0x6fd5de64, 0x888373f0, 0xf088fb83, 0x6fb1fb4a, 0x4a6f94b1, 0x7296ca5c, 0x5c72b896, 0x246c5438, 0x3824706c, 0xf1085f57, 0x57f1ae08, 0xc7522173, 0x73c7e652, 0x51f36497, 0x975135f3 58 | , 0x2365aecb, 0xcb238d65, 0x7c8425a1, 0xa17c5984, 0x9cbf57e8, 0xe89ccbbf, 0x21635d3e, 0x3e217c63, 0xdd7cea96, 0x96dd377c, 0xdc7f1e61, 0x61dcc27f, 0x86919c0d, 0xd861a91, 0x85949b0f, 0xf851e94 59 | , 0x90ab4be0, 0xe090dbab, 0x42c6ba7c, 0x7c42f8c6, 0xc4572671, 0x71c4e257, 0xaae529cc, 0xccaa83e5, 0xd873e390, 0x90d83b73, 0x50f0906, 0x6050c0f, 0x103f4f7, 0xf701f503, 0x12362a1c, 0x1c123836 60 | , 0xa3fe3cc2, 0xc2a39ffe, 0x5fe18b6a, 0x6a5fd4e1, 0xf910beae, 0xaef94710, 0xd06b0269, 0x69d0d26b, 0x91a8bf17, 0x17912ea8, 0x58e87199, 0x995829e8, 0x2769533a, 0x3a277469, 0xb9d0f727, 0x27b94ed0 61 | , 0x384891d9, 0xd938a948, 0x1335deeb, 0xeb13cd35, 0xb3cee52b, 0x2bb356ce, 0x33557722, 0x22334455, 0xbbd604d2, 0xd2bbbfd6, 0x709039a9, 0xa9704990, 0x89808707, 0x7890e80, 0xa7f2c133, 0x33a766f2 62 | , 0xb6c1ec2d, 0x2db65ac1, 0x22665a3c, 0x3c227866, 0x92adb815, 0x15922aad, 0x2060a9c9, 0xc9208960, 0x49db5c87, 0x874915db, 0xff1ab0aa, 0xaaff4f1a, 0x7888d850, 0x5078a088, 0x7a8e2ba5, 0xa57a518e 63 | , 0x8f8a8903, 0x38f068a, 0xf8134a59, 0x59f8b213, 0x809b9209, 0x980129b, 0x1739231a, 0x1a173439, 0xda751065, 0x65daca75, 0x315384d7, 0xd731b553, 0xc651d584, 0x84c61351, 0xb8d303d0, 0xd0b8bbd3 64 | , 0xc35edc82, 0x82c31f5e, 0xb0cbe229, 0x29b052cb, 0x7799c35a, 0x5a77b499, 0x11332d1e, 0x1e113c33, 0xcb463d7b, 0x7bcbf646, 0xfc1fb7a8, 0xa8fc4b1f, 0xd6610c6d, 0x6dd6da61, 0x3a4e622c, 0x2c3a584e}; 65 | 66 | #endif /* __tables_h */ 67 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/skein_port.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | #ifndef _SKEIN_PORT_H_ 30 | #define _SKEIN_PORT_H_ 31 | 32 | #include 33 | #include 34 | 35 | #ifndef RETURN_VALUES 36 | # define RETURN_VALUES 37 | # if defined( DLL_EXPORT ) 38 | # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) 39 | # define VOID_RETURN __declspec( dllexport ) void __stdcall 40 | # define INT_RETURN __declspec( dllexport ) int __stdcall 41 | # elif defined( __GNUC__ ) 42 | # define VOID_RETURN __declspec( __dllexport__ ) void 43 | # define INT_RETURN __declspec( __dllexport__ ) int 44 | # else 45 | # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers 46 | # endif 47 | # elif defined( DLL_IMPORT ) 48 | # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) 49 | # define VOID_RETURN __declspec( dllimport ) void __stdcall 50 | # define INT_RETURN __declspec( dllimport ) int __stdcall 51 | # elif defined( __GNUC__ ) 52 | # define VOID_RETURN __declspec( __dllimport__ ) void 53 | # define INT_RETURN __declspec( __dllimport__ ) int 54 | # else 55 | # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers 56 | # endif 57 | # elif defined( __WATCOMC__ ) 58 | # define VOID_RETURN void __cdecl 59 | # define INT_RETURN int __cdecl 60 | # else 61 | # define VOID_RETURN void 62 | # define INT_RETURN int 63 | # endif 64 | #endif 65 | 66 | /* These defines are used to declare buffers in a way that allows 67 | faster operations on longer variables to be used. In all these 68 | defines 'size' must be a power of 2 and >= 8 69 | 70 | dec_unit_type(size,x) declares a variable 'x' of length 71 | 'size' bits 72 | 73 | dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize' 74 | bytes defined as an array of variables 75 | each of 'size' bits (bsize must be a 76 | multiple of size / 8) 77 | 78 | ptr_cast(x,size) casts a pointer to a pointer to a 79 | varaiable of length 'size' bits 80 | */ 81 | 82 | #define ui_type(size) uint##size##_t 83 | #define dec_unit_type(size,x) typedef ui_type(size) x 84 | #define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)] 85 | #define ptr_cast(x,size) ((ui_type(size)*)(x)) 86 | 87 | typedef unsigned int uint_t; /* native unsigned integer */ 88 | typedef uint8_t u08b_t; /* 8-bit unsigned integer */ 89 | typedef uint64_t u64b_t; /* 64-bit unsigned integer */ 90 | 91 | #ifndef RotL_64 92 | #define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N)))) 93 | #endif 94 | 95 | /* 96 | * Skein is "natively" little-endian (unlike SHA-xxx), for optimal 97 | * performance on x86 CPUs. The Skein code requires the following 98 | * definitions for dealing with endianness: 99 | * 100 | * SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian 101 | * Skein_Put64_LSB_First 102 | * Skein_Get64_LSB_First 103 | * Skein_Swap64 104 | * 105 | * If SKEIN_NEED_SWAP is defined at compile time, it is used here 106 | * along with the portable versions of Put64/Get64/Swap64, which 107 | * are slow in general. 108 | * 109 | * Otherwise, an "auto-detect" of endianness is attempted below. 110 | * If the default handling doesn't work well, the user may insert 111 | * platform-specific code instead (e.g., for big-endian CPUs). 112 | * 113 | */ 114 | #ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */ 115 | 116 | 117 | #include "int-util.h" 118 | 119 | #define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ 120 | #define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ 121 | 122 | #if BYTE_ORDER == LITTLE_ENDIAN 123 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 124 | #endif 125 | 126 | #if BYTE_ORDER == BIG_ENDIAN 127 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 128 | #endif 129 | 130 | /* special handler for IA64, which may be either endianness (?) */ 131 | /* here we assume little-endian, but this may need to be changed */ 132 | #if defined(__ia64) || defined(__ia64__) || defined(_M_IA64) 133 | # define PLATFORM_MUST_ALIGN (1) 134 | #ifndef PLATFORM_BYTE_ORDER 135 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 136 | #endif 137 | #endif 138 | 139 | #ifndef PLATFORM_MUST_ALIGN 140 | # define PLATFORM_MUST_ALIGN (0) 141 | #endif 142 | 143 | 144 | #if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN 145 | /* here for big-endian CPUs */ 146 | #define SKEIN_NEED_SWAP (1) 147 | #elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN 148 | /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */ 149 | #define SKEIN_NEED_SWAP (0) 150 | #if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */ 151 | #define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt) 152 | #define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt)) 153 | #endif 154 | #else 155 | #error "Skein needs endianness setting!" 156 | #endif 157 | 158 | #endif /* ifndef SKEIN_NEED_SWAP */ 159 | 160 | /* 161 | ****************************************************************** 162 | * Provide any definitions still needed. 163 | ****************************************************************** 164 | */ 165 | #ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */ 166 | #if SKEIN_NEED_SWAP 167 | #define Skein_Swap64(w64) \ 168 | ( (( ((u64b_t)(w64)) & 0xFF) << 56) | \ 169 | (((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \ 170 | (((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \ 171 | (((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \ 172 | (((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \ 173 | (((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \ 174 | (((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \ 175 | (((((u64b_t)(w64)) >>56) & 0xFF) ) ) 176 | #else 177 | #define Skein_Swap64(w64) (w64) 178 | #endif 179 | #endif /* ifndef Skein_Swap64 */ 180 | 181 | 182 | #ifndef Skein_Put64_LSB_First 183 | void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt) 184 | #ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ 185 | { /* this version is fully portable (big-endian or little-endian), but slow */ 186 | size_t n; 187 | 188 | for (n=0;n>3] >> (8*(n&7))); 190 | } 191 | #else 192 | ; /* output only the function prototype */ 193 | #endif 194 | #endif /* ifndef Skein_Put64_LSB_First */ 195 | 196 | 197 | #ifndef Skein_Get64_LSB_First 198 | void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt) 199 | #ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ 200 | { /* this version is fully portable (big-endian or little-endian), but slow */ 201 | size_t n; 202 | 203 | for (n=0;n<8*wCnt;n+=8) 204 | dst[n/8] = (((u64b_t) src[n ]) ) + 205 | (((u64b_t) src[n+1]) << 8) + 206 | (((u64b_t) src[n+2]) << 16) + 207 | (((u64b_t) src[n+3]) << 24) + 208 | (((u64b_t) src[n+4]) << 32) + 209 | (((u64b_t) src[n+5]) << 40) + 210 | (((u64b_t) src[n+6]) << 48) + 211 | (((u64b_t) src[n+7]) << 56) ; 212 | } 213 | #else 214 | ; /* output only the function prototype */ 215 | #endif 216 | #endif /* ifndef Skein_Get64_LSB_First */ 217 | 218 | #endif /* ifndef _SKEIN_PORT_H_ */ 219 | -------------------------------------------------------------------------------- /MoneroKit/MoneroMiner.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroMiner.m 3 | // MoneroKit 4 | // 5 | // Created by Yury Popov on 08.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroKit.h" 10 | #import "MoneroPoolConnection.h" 11 | #import "MoneroBackend.h" 12 | 13 | @interface MoneroNetworkLoopThread: NSThread 14 | @property (nonatomic, readonly, nonnull) NSRunLoop *runLoop; 15 | @end 16 | 17 | @implementation MoneroNetworkLoopThread { 18 | NSRunLoop *_runLoop; 19 | } 20 | - (void)main { 21 | _runLoop = [NSRunLoop currentRunLoop]; 22 | while (![self isCancelled]) { 23 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0.5]; 24 | [_runLoop runUntilDate:date]; 25 | [NSThread sleepUntilDate:date]; 26 | } 27 | } 28 | - (NSRunLoop *)runLoop { 29 | while (!_runLoop) [NSThread sleepForTimeInterval:0.01]; 30 | return _runLoop; 31 | } 32 | @end 33 | 34 | @interface MoneroMiner () 35 | @property (atomic, nonnull) NSMutableArray *connections; 36 | @property (atomic, nonnull) MoneroBackend* backend; 37 | @property (atomic, nonnull) MoneroNetworkLoopThread *networkThread; 38 | @property (atomic, nonnull) NSMutableDictionary *jobs; 39 | @property (atomic, nonnull) NSMutableDictionary *scores; 40 | @property (atomic, nullable) NSString *currentWorker; 41 | @property (atomic, nullable) NSDate *currentWorkerStart; 42 | @property (atomic, nonnull) NSTimer *balanceTimer; 43 | @property (atomic, nonnull) dispatch_queue_t bg_queue; 44 | @property (atomic) BOOL reconnect; 45 | @end 46 | 47 | @implementation MoneroMiner 48 | 49 | + (NSString *)baseAddress:(NSString *)walletAddress { 50 | static NSString *const chars = @"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 51 | NSCharacterSet *base58Chars = [NSCharacterSet characterSetWithCharactersInString:chars]; 52 | NSCharacterSet *nonBase58Chars = [base58Chars invertedSet]; 53 | return [[walletAddress componentsSeparatedByCharactersInSet:nonBase58Chars] firstObject]; 54 | } 55 | 56 | - (instancetype)init { 57 | if (self = [super init]) { 58 | self.networkThread = [MoneroNetworkLoopThread new]; 59 | self.networkThread.qualityOfService = NSQualityOfServiceBackground; 60 | [self.networkThread start]; 61 | 62 | self.bg_queue = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0); 63 | self.connections = [NSMutableArray new]; 64 | self.jobs = [NSMutableDictionary new]; 65 | self.scores = [NSMutableDictionary new]; 66 | 67 | self.backend = [MoneroBackend new]; 68 | self.backend.delegateQueue = self.bg_queue; 69 | [self.backend setDelegate:self]; 70 | 71 | self.reconnect = false; 72 | self.cpuLimit = 1; 73 | self.metalLimit = 1; 74 | } 75 | return self; 76 | } 77 | 78 | - (void)dealloc { 79 | [self.networkThread cancel]; 80 | } 81 | 82 | - (double)cpuLimit { 83 | return [self.backend cpuLimit]; 84 | } 85 | 86 | - (double)metalLimit { 87 | return [self.backend metalLimit]; 88 | } 89 | 90 | - (void)setWorkers:(NSArray *)workers { 91 | _workers = [workers sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"weight" ascending:NO]]]; 92 | } 93 | 94 | - (void)setCPULimit:(double)cpuLimit { 95 | [self.backend setCPULimit:cpuLimit]; 96 | } 97 | 98 | - (void)setMetalLimit:(double)metalLimit { 99 | [self.backend setMetalLimit:metalLimit]; 100 | } 101 | 102 | - (void)startMining { 103 | self.reconnect = true; 104 | for (MoneroPoolConnection *conn in self.connections) { 105 | [conn close]; 106 | } 107 | [self.connections removeAllObjects]; 108 | for (MoneroWorker *worker in self.workers) { 109 | MoneroPoolConnection *conn = [MoneroPoolConnection connectionWithHost:worker.poolHost port:worker.poolPort ssl:worker.poolSecure walletAddress:worker.walletAddress password:worker.password]; 110 | [conn setRunLoop:self.networkThread.runLoop]; 111 | [conn setDelegate:self]; 112 | [conn setIdentifier:worker.identifier]; 113 | [self.connections addObject:conn]; 114 | [conn connect]; 115 | } 116 | self.balanceTimer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(balanceJobs) userInfo:nil repeats:YES]; 117 | [self.networkThread.runLoop addTimer:self.balanceTimer forMode:NSRunLoopCommonModes]; 118 | } 119 | 120 | - (void)stopMining { 121 | [self.balanceTimer invalidate]; 122 | self.reconnect = false; 123 | for (MoneroPoolConnection *conn in self.connections) { 124 | [conn close]; 125 | } 126 | [self.connections removeAllObjects]; 127 | [self.jobs removeAllObjects]; 128 | [self balanceJobs]; 129 | } 130 | 131 | - (BOOL)active { 132 | return self.reconnect && self.connections.count > 0; 133 | } 134 | 135 | - (void)connection:(MoneroPoolConnection *)connection receivedCommand:(NSString *)command withOptions:(NSDictionary *)options callback:(MoneroPoolConnectionCallback)callback { 136 | NSLog(@"%@ %@", command, options); 137 | callback(nil, nil); 138 | } 139 | 140 | - (void)connection:(MoneroPoolConnection *)connection error:(NSError *)error { 141 | id delegate = [self delegate]; 142 | [delegate miningError:error stopped:NO]; 143 | [self.jobs removeObjectForKey:connection.identifier]; 144 | [self balanceJobs]; 145 | __weak __typeof__(self) wself = self; 146 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(100 * NSEC_PER_MSEC)), self.bg_queue, ^{ 147 | __strong __typeof__(wself) self = wself; 148 | if (self && self.reconnect) [connection connect]; 149 | }); 150 | } 151 | 152 | - (void)connection:(MoneroPoolConnection *)connection receivedNewJob:(MoneroBackendJob *)job { 153 | id delegate = [self delegate]; 154 | MoneroBackendJob *oldJob = [self.jobs objectForKey:connection.identifier]; 155 | MoneroWorker *worker = [[self.workers filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"identifier == %@", connection.identifier]] firstObject]; 156 | if ([worker nicehash]) job.nicehash = YES; 157 | if (oldJob) { 158 | if ([oldJob.jobId isEqualToString:job.jobId]) { 159 | return; 160 | } 161 | if (oldJob.difficulty != job.difficulty) { 162 | [delegate difficultyChanged:(NSUInteger)job.difficulty forWorker:connection.identifier]; 163 | } 164 | if ([oldJob.blob isEqualToData:job.blob]) { 165 | oldJob.jobId = job.jobId; 166 | oldJob.target = job.target; 167 | return; 168 | } 169 | if (memcmp(oldJob.prevBlockHash.bytes, job.prevBlockHash.bytes, sizeof(job.prevBlockHash.bytes)) != 0) { 170 | [delegate blockFoundForWorker:connection.identifier]; 171 | } 172 | } else { 173 | [delegate difficultyChanged:(NSUInteger)job.difficulty forWorker:connection.identifier]; 174 | } 175 | [self.jobs setObject:job forKey:connection.identifier]; 176 | [self balanceJobs]; 177 | } 178 | 179 | - (void)balanceJobs { 180 | MoneroBackendJob *currentJob = [self.backend currentJob]; 181 | if (_currentWorkerStart != nil && (-[_currentWorkerStart timeIntervalSinceNow] < 10)) { 182 | MoneroBackendJob *job = [self.jobs objectForKey:_currentWorker]; 183 | if ([job.jobId isEqualToString:currentJob.jobId]) return; 184 | [self.backend setCurrentJob:job]; 185 | return; 186 | } 187 | 188 | double totalWeight = 0; 189 | double totalScore = 0 - [_currentWorkerStart timeIntervalSinceNow]; 190 | 191 | for (MoneroWorker *w in _workers) { 192 | totalWeight += w.weight; 193 | totalScore += [[_scores objectForKey:w.identifier] doubleValue]; 194 | } 195 | 196 | if (totalScore == 0 || totalWeight == 0) { 197 | [self pickJobForWorkers:_workers]; 198 | return; 199 | } 200 | 201 | NSMutableDictionary *balanceWeights = [NSMutableDictionary new]; 202 | 203 | for (MoneroWorker *w in _workers) { 204 | double dw = w.weight / totalWeight; 205 | double ws = [[_scores objectForKey:w.identifier] doubleValue]; 206 | if ([_currentWorker isEqualToString:w.identifier]) ws -= [_currentWorkerStart timeIntervalSinceNow]; 207 | double cw = ws / totalScore; 208 | double bw = MIN(dw / cw, (double)1); 209 | [balanceWeights setObject:@(bw) forKey:w.identifier]; 210 | } 211 | 212 | [self pickJobForWorkers:[_workers sortedArrayUsingComparator:^NSComparisonResult(MoneroWorker *w1, MoneroWorker *w2) { 213 | NSNumber *bw1 = [balanceWeights objectForKey:w1.identifier]; 214 | NSNumber *bw2 = [balanceWeights objectForKey:w2.identifier]; 215 | return [bw2 compare:bw1]; 216 | }]]; 217 | } 218 | 219 | - (void)pickJobForWorkers:(NSArray*)workers { 220 | MoneroBackendJob *currentJob = [self.backend currentJob]; 221 | 222 | for (MoneroWorker *w in workers) { 223 | MoneroBackendJob *job = [_jobs objectForKey:w.identifier]; 224 | if (job != nil) { 225 | if ([job.jobId isEqualToString:currentJob.jobId]) return; 226 | if (![w.identifier isEqualToString:_currentWorker]) { 227 | if (_currentWorkerStart != nil && _currentWorker != nil) { 228 | [_scores setObject:@([_scores objectForKey:_currentWorker].doubleValue - [_currentWorkerStart timeIntervalSinceNow]) forKey:_currentWorker]; 229 | } 230 | _currentWorker = w.identifier; 231 | _currentWorkerStart = [NSDate new]; 232 | } 233 | [self.backend setCurrentJob:job]; 234 | return; 235 | } 236 | } 237 | if (_currentWorkerStart != nil && _currentWorker != nil) { 238 | [_scores setObject:@([_scores objectForKey:_currentWorker].doubleValue - [_currentWorkerStart timeIntervalSinceNow]) forKey:_currentWorker]; 239 | } 240 | _currentWorker = nil; 241 | _currentWorkerStart = nil; 242 | [self.backend setCurrentJob:nil]; 243 | } 244 | 245 | - (MoneroPoolConnection*)connectionWithId:(NSString*)connId { 246 | return [[self.connections filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"identifier == %@", connId]] firstObject]; 247 | } 248 | 249 | - (MoneroPoolConnection*)connectionForJob:(NSString*)jobId { 250 | for (NSString *connId in self.jobs) { 251 | MoneroBackendJob *job = self.jobs[connId]; 252 | if ([job.jobId isEqualToString:jobId]) { 253 | return [self connectionWithId:connId]; 254 | } 255 | } 256 | return nil; 257 | } 258 | 259 | - (void)foundResult:(const struct MoneroHash*)result withNonce:(uint32_t)nonce forJobId:(NSString *)jobId { 260 | MoneroPoolConnection *conn = [self connectionForJob:jobId]; 261 | if (conn == nil) return; 262 | NSUInteger resDiff = (NSUInteger)(0xFFFFFFFFFFFFFFFFLLU / result->lluints[3]); 263 | __weak __typeof__(self) wself = self; 264 | NSString *cid = conn.identifier; 265 | [conn submitShare:result withNonce:nonce forJobId:jobId callback:^(NSError *_Nullable error){ 266 | __strong __typeof__(wself) self = wself; 267 | if (self) { 268 | dispatch_async(self.bg_queue, ^{ 269 | __strong __typeof__(wself) self = wself; 270 | if (self) { 271 | id delegate = [self delegate]; 272 | if (error == nil) { 273 | [delegate acceptedResult:resDiff forWorker:cid]; 274 | } else { 275 | [delegate miningError:error stopped:NO]; 276 | } 277 | } 278 | }); 279 | } 280 | }]; 281 | } 282 | 283 | - (double)hashRate { 284 | return [self.backend hashRate]; 285 | } 286 | 287 | @end 288 | -------------------------------------------------------------------------------- /MoneroKit/MoneroKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroKit.h 3 | // MoneroKit 4 | // 5 | // Created by Yury Popov on 07.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | /** 14 | * @brief Miner delegate provides callbacks for most important mining events 15 | */ 16 | @protocol MoneroMinerDelegate 17 | /** 18 | * @brief Callback for result acceptance by pool 19 | * @param result Result difficulty 20 | * @param workerId Worker identifier 21 | */ 22 | - (void)acceptedResult:(NSUInteger)result forWorker:(NSString*)workerId; 23 | /** 24 | * @brief Callback for mining difficulty change by pool 25 | * @param difficulty New mining difficulty 26 | * @param workerId Worker identifier 27 | */ 28 | - (void)difficultyChanged:(NSUInteger)difficulty forWorker:(NSString*)workerId; 29 | /** 30 | * @brief Callback for new found block by pool 31 | * @param workerId Worker identifier 32 | */ 33 | - (void)blockFoundForWorker:(NSString*)workerId; 34 | /** 35 | * @brief Callback for mining errors 36 | * @param error Error object 37 | * @param stopped Flag that indicates that mining have been stopped 38 | */ 39 | - (void)miningError:(NSError*)error stopped:(BOOL)stopped; 40 | @end 41 | 42 | /** 43 | * @brief Worker descriptor 44 | */ 45 | @interface MoneroWorker : NSObject 46 | - (instancetype)init NS_UNAVAILABLE; 47 | /** 48 | * @brief Instantiate a new worker descriptor 49 | * @param identifier Worker identifier for use in callbacks 50 | * @param host Mining pool hostname 51 | * @param port Mining pool port 52 | * @param secure Flag that indicates that pool uses SSL for connection 53 | * @param nicehash Flag that indicates that pool uses Nicehash algorithm 54 | * @param wallet Wallet address for pool payouts, or username 55 | * @param password Password to use for authentication in mining pool 56 | * @param weight Weight of worker for load-balancing 57 | */ 58 | + (instancetype)workerWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString*)wallet password:(NSString*)password weight:(double)weight __SWIFT_UNAVAILABLE; 59 | /** 60 | * @brief Instantiate a new worker descriptor 61 | * @param identifier Worker identifier for use in callbacks 62 | * @param host Mining pool hostname 63 | * @param port Mining pool port 64 | * @param secure Flag that indicates that pool uses SSL for connection 65 | * @param nicehash Flag that indicates that pool uses Nicehash algorithm 66 | * @param wallet Wallet address for pool payouts, or username 67 | * @param password Password to use for authentication in mining pool 68 | */ 69 | + (instancetype)workerWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString*)wallet password:(NSString*)password __SWIFT_UNAVAILABLE; 70 | /** 71 | * @brief Instantiate a new worker descriptor 72 | * @param identifier Worker identifier for use in callbacks 73 | * @param host Mining pool hostname 74 | * @param port Mining pool port 75 | * @param secure Flag that indicates that pool uses SSL for connection 76 | * @param nicehash Flag that indicates that pool uses Nicehash algorithm 77 | * @param wallet Wallet address for pool payouts, or username 78 | */ 79 | + (instancetype)workerWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString*)wallet __SWIFT_UNAVAILABLE; 80 | /** 81 | * @brief Instantiate a new worker descriptor 82 | * @param identifier Worker identifier for use in callbacks 83 | * @param host Mining pool hostname 84 | * @param port Mining pool port 85 | * @param secure Flag that indicates that pool uses SSL for connection 86 | * @param wallet Wallet address for pool payouts, or username 87 | * @param password Password to use for authentication in mining pool 88 | * @param weight Weight of worker for load-balancing 89 | */ 90 | + (instancetype)workerWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString*)wallet password:(NSString*)password weight:(double)weight __SWIFT_UNAVAILABLE; 91 | /** 92 | * @brief Instantiate a new worker descriptor 93 | * @param identifier Worker identifier for use in callbacks 94 | * @param host Mining pool hostname 95 | * @param port Mining pool port 96 | * @param secure Flag that indicates that pool uses SSL for connection 97 | * @param wallet Wallet address for pool payouts, or username 98 | * @param password Password to use for authentication in mining pool 99 | */ 100 | + (instancetype)workerWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString*)wallet password:(NSString*)password __SWIFT_UNAVAILABLE; 101 | /** 102 | * @brief Instantiate a new worker descriptor 103 | * @param identifier Worker identifier for use in callbacks 104 | * @param host Mining pool hostname 105 | * @param port Mining pool port 106 | * @param secure Flag that indicates that pool uses SSL for connection 107 | * @param wallet Wallet address for pool payouts, or username 108 | */ 109 | + (instancetype)workerWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString*)wallet __SWIFT_UNAVAILABLE; 110 | /** 111 | * @brief Initializes a worker descriptor 112 | * @param identifier Worker identifier for use in callbacks 113 | * @param host Mining pool hostname 114 | * @param port Mining pool port 115 | * @param secure Flag that indicates that pool uses SSL for connection 116 | * @param nicehash Flag that indicates that pool uses Nicehash algorithm 117 | * @param wallet Wallet address for pool payouts, or username 118 | * @param password Password to use for authentication in mining pool 119 | * @param weight Weight of worker for load-balancing 120 | */ 121 | - (instancetype)initWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString*)wallet password:(NSString*)password weight:(double)weight; 122 | /** 123 | * @brief Initializes a worker descriptor 124 | * @param identifier Worker identifier for use in callbacks 125 | * @param host Mining pool hostname 126 | * @param port Mining pool port 127 | * @param secure Flag that indicates that pool uses SSL for connection 128 | * @param nicehash Flag that indicates that pool uses Nicehash algorithm 129 | * @param wallet Wallet address for pool payouts, or username 130 | * @param password Password to use for authentication in mining pool 131 | */ 132 | - (instancetype)initWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString*)wallet password:(NSString*)password; 133 | /** 134 | * @brief Initializes a worker descriptor 135 | * @param identifier Worker identifier for use in callbacks 136 | * @param host Mining pool hostname 137 | * @param port Mining pool port 138 | * @param secure Flag that indicates that pool uses SSL for connection 139 | * @param nicehash Flag that indicates that pool uses Nicehash algorithm 140 | * @param wallet Wallet address for pool payouts, or username 141 | */ 142 | - (instancetype)initWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure nicehash:(BOOL)nicehash walletAddress:(NSString*)wallet; 143 | /** 144 | * @brief Initializes a worker descriptor 145 | * @param identifier Worker identifier for use in callbacks 146 | * @param host Mining pool hostname 147 | * @param port Mining pool port 148 | * @param secure Flag that indicates that pool uses SSL for connection 149 | * @param wallet Wallet address for pool payouts, or username 150 | * @param password Password to use for authentication in mining pool 151 | * @param weight Weight of worker for load-balancing 152 | */ 153 | - (instancetype)initWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString*)wallet password:(NSString*)password weight:(double)weight; 154 | /** 155 | * @brief Initializes a worker descriptor 156 | * @param identifier Worker identifier for use in callbacks 157 | * @param host Mining pool hostname 158 | * @param port Mining pool port 159 | * @param secure Flag that indicates that pool uses SSL for connection 160 | * @param wallet Wallet address for pool payouts, or username 161 | * @param password Password to use for authentication in mining pool 162 | */ 163 | - (instancetype)initWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString*)wallet password:(NSString*)password; 164 | /** 165 | * @brief Initializes a worker descriptor 166 | * @param identifier Worker identifier for use in callbacks 167 | * @param host Mining pool hostname 168 | * @param port Mining pool port 169 | * @param secure Flag that indicates that pool uses SSL for connection 170 | * @param wallet Wallet address for pool payouts, or username 171 | */ 172 | - (instancetype)initWithIdentifier:(NSString*)identifier poolHost:(NSString*)host port:(uint16_t)port secure:(BOOL)secure walletAddress:(NSString*)wallet; 173 | /** 174 | * @brief Worker identifier for use in callbacks 175 | */ 176 | @property (atomic, copy) NSString *identifier; 177 | /** 178 | * @brief Mining pool hostname 179 | */ 180 | @property (atomic, copy) NSString *poolHost; 181 | /** 182 | * @brief Mining pool port 183 | */ 184 | @property (atomic) uint16_t poolPort; 185 | /** 186 | * @brief Flag that indicates that pool uses SSL for connection 187 | */ 188 | @property (atomic) BOOL poolSecure; 189 | /** 190 | * @brief Flag that indicates that pool uses Nicehash algorithm 191 | */ 192 | @property (atomic) BOOL nicehash; 193 | /** 194 | * @brief Wallet address for pool payouts, or username 195 | */ 196 | @property (atomic, copy) NSString *walletAddress; 197 | /** 198 | * @brief Password to use for authentication in mining pool 199 | */ 200 | @property (atomic, copy) NSString *password; 201 | /** 202 | * @brief Weight of worker for load-balancing 203 | */ 204 | @property (atomic) double weight; 205 | @end 206 | 207 | /** 208 | * @brief Monero mining coordinator 209 | */ 210 | @interface MoneroMiner : NSObject 211 | /** 212 | * @brief Extract base address from full address that includes additional parameters 213 | * @param walletAddress Full address that includes additional parameters (e.g. worker identifier and/or difficulty set) 214 | * @return Base wallet address 215 | */ 216 | + (NSString*)baseAddress:(NSString*)walletAddress; 217 | /** 218 | * @brief Mining events delegate 219 | */ 220 | @property (nullable, weak, nonatomic) id delegate; 221 | /** 222 | * @brief Mining workers 223 | * @discussion If more than one specified, uses load-balancing based on worker weights 224 | */ 225 | @property (nonatomic, copy) NSArray *workers; 226 | /** 227 | * @brief CPU usage limit (0 ... 1) 228 | * @discussion Set to 0 to disable CPU mining, set to 1 to maximum CPU mining efficiency 229 | */ 230 | @property (nonatomic, setter=setCPULimit:) double cpuLimit; 231 | /** 232 | * @brief Metal usage limit (0 ... 1) 233 | * @discussion Set to 0 to disable Metal mining, set to 1 to maximum Metal mining efficiency 234 | */ 235 | @property (nonatomic) double metalLimit; 236 | /** 237 | * @brief Indicates that mining is currently active 238 | */ 239 | @property (nonatomic, readonly) BOOL active; 240 | /** 241 | * @brief Reports current hash rate (hash / second) 242 | */ 243 | @property (nonatomic, readonly) double hashRate; 244 | /** 245 | * @brief Start mining process 246 | */ 247 | - (void)startMining; 248 | /** 249 | * @brief Stop mining process 250 | */ 251 | - (void)stopMining; 252 | @end 253 | 254 | NS_ASSUME_NONNULL_END 255 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/groestl.c: -------------------------------------------------------------------------------- 1 | /* hash.c April 2012 2 | * Groestl ANSI C code optimised for 32-bit machines 3 | * Author: Thomas Krinninger 4 | * 5 | * This work is based on the implementation of 6 | * Soeren S. Thomsen and Krystian Matusiewicz 7 | * 8 | * 9 | */ 10 | 11 | #include 12 | #include "groestl.h" 13 | #include "groestl_tables.h" 14 | 15 | #define P_TYPE 0 16 | #define Q_TYPE 1 17 | 18 | const uint8_t shift_Values[2][8] = {{0,1,2,3,4,5,6,7},{1,3,5,7,0,2,4,6}}; 19 | 20 | const uint8_t indices_cyclic[15] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6}; 21 | 22 | 23 | #define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1<<(8*amount_bytes))|(v2>>(8*(4-amount_bytes))); \ 24 | v2 = (v2<<(8*amount_bytes))|(v1>>(8*(4-amount_bytes))); \ 25 | v1 = temp_var;} 26 | 27 | 28 | #define COLUMN(x,y,i,c0,c1,c2,c3,c4,c5,c6,c7,tv1,tv2,tu,tl,t) \ 29 | tu = T[2*(uint32_t)x[4*c0+0]]; \ 30 | tl = T[2*(uint32_t)x[4*c0+0]+1]; \ 31 | tv1 = T[2*(uint32_t)x[4*c1+1]]; \ 32 | tv2 = T[2*(uint32_t)x[4*c1+1]+1]; \ 33 | ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \ 34 | tu ^= tv1; \ 35 | tl ^= tv2; \ 36 | tv1 = T[2*(uint32_t)x[4*c2+2]]; \ 37 | tv2 = T[2*(uint32_t)x[4*c2+2]+1]; \ 38 | ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \ 39 | tu ^= tv1; \ 40 | tl ^= tv2; \ 41 | tv1 = T[2*(uint32_t)x[4*c3+3]]; \ 42 | tv2 = T[2*(uint32_t)x[4*c3+3]+1]; \ 43 | ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \ 44 | tu ^= tv1; \ 45 | tl ^= tv2; \ 46 | tl ^= T[2*(uint32_t)x[4*c4+0]]; \ 47 | tu ^= T[2*(uint32_t)x[4*c4+0]+1]; \ 48 | tv1 = T[2*(uint32_t)x[4*c5+1]]; \ 49 | tv2 = T[2*(uint32_t)x[4*c5+1]+1]; \ 50 | ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \ 51 | tl ^= tv1; \ 52 | tu ^= tv2; \ 53 | tv1 = T[2*(uint32_t)x[4*c6+2]]; \ 54 | tv2 = T[2*(uint32_t)x[4*c6+2]+1]; \ 55 | ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \ 56 | tl ^= tv1; \ 57 | tu ^= tv2; \ 58 | tv1 = T[2*(uint32_t)x[4*c7+3]]; \ 59 | tv2 = T[2*(uint32_t)x[4*c7+3]+1]; \ 60 | ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \ 61 | tl ^= tv1; \ 62 | tu ^= tv2; \ 63 | y[i] = tu; \ 64 | y[i+1] = tl; 65 | 66 | 67 | /* compute one round of P (short variants) */ 68 | static void RND512P(uint8_t *x, uint32_t *y, uint32_t r) { 69 | uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp; 70 | uint32_t* x32 = (uint32_t*)x; 71 | x32[ 0] ^= 0x00000000^r; 72 | x32[ 2] ^= 0x00000010^r; 73 | x32[ 4] ^= 0x00000020^r; 74 | x32[ 6] ^= 0x00000030^r; 75 | x32[ 8] ^= 0x00000040^r; 76 | x32[10] ^= 0x00000050^r; 77 | x32[12] ^= 0x00000060^r; 78 | x32[14] ^= 0x00000070^r; 79 | COLUMN(x,y, 0, 0, 2, 4, 6, 9, 11, 13, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 80 | COLUMN(x,y, 2, 2, 4, 6, 8, 11, 13, 15, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 81 | COLUMN(x,y, 4, 4, 6, 8, 10, 13, 15, 1, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 82 | COLUMN(x,y, 6, 6, 8, 10, 12, 15, 1, 3, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 83 | COLUMN(x,y, 8, 8, 10, 12, 14, 1, 3, 5, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 84 | COLUMN(x,y,10, 10, 12, 14, 0, 3, 5, 7, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 85 | COLUMN(x,y,12, 12, 14, 0, 2, 5, 7, 9, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 86 | COLUMN(x,y,14, 14, 0, 2, 4, 7, 9, 11, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 87 | } 88 | 89 | /* compute one round of Q (short variants) */ 90 | static void RND512Q(uint8_t *x, uint32_t *y, uint32_t r) { 91 | uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp; 92 | uint32_t* x32 = (uint32_t*)x; 93 | x32[ 0] = ~x32[ 0]; 94 | x32[ 1] ^= 0xffffffff^r; 95 | x32[ 2] = ~x32[ 2]; 96 | x32[ 3] ^= 0xefffffff^r; 97 | x32[ 4] = ~x32[ 4]; 98 | x32[ 5] ^= 0xdfffffff^r; 99 | x32[ 6] = ~x32[ 6]; 100 | x32[ 7] ^= 0xcfffffff^r; 101 | x32[ 8] = ~x32[ 8]; 102 | x32[ 9] ^= 0xbfffffff^r; 103 | x32[10] = ~x32[10]; 104 | x32[11] ^= 0xafffffff^r; 105 | x32[12] = ~x32[12]; 106 | x32[13] ^= 0x9fffffff^r; 107 | x32[14] = ~x32[14]; 108 | x32[15] ^= 0x8fffffff^r; 109 | COLUMN(x,y, 0, 2, 6, 10, 14, 1, 5, 9, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 110 | COLUMN(x,y, 2, 4, 8, 12, 0, 3, 7, 11, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 111 | COLUMN(x,y, 4, 6, 10, 14, 2, 5, 9, 13, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 112 | COLUMN(x,y, 6, 8, 12, 0, 4, 7, 11, 15, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 113 | COLUMN(x,y, 8, 10, 14, 2, 6, 9, 13, 1, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 114 | COLUMN(x,y,10, 12, 0, 4, 8, 11, 15, 3, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 115 | COLUMN(x,y,12, 14, 2, 6, 10, 13, 1, 5, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 116 | COLUMN(x,y,14, 0, 4, 8, 12, 15, 3, 7, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp); 117 | } 118 | 119 | /* compute compression function (short variants) */ 120 | static void F512(uint32_t *h, const uint32_t *m) { 121 | int i; 122 | uint32_t Ptmp[2*COLS512]; 123 | uint32_t Qtmp[2*COLS512]; 124 | uint32_t y[2*COLS512]; 125 | uint32_t z[2*COLS512]; 126 | 127 | for (i = 0; i < 2*COLS512; i++) { 128 | z[i] = m[i]; 129 | Ptmp[i] = h[i]^m[i]; 130 | } 131 | 132 | /* compute Q(m) */ 133 | RND512Q((uint8_t*)z, y, 0x00000000); 134 | RND512Q((uint8_t*)y, z, 0x01000000); 135 | RND512Q((uint8_t*)z, y, 0x02000000); 136 | RND512Q((uint8_t*)y, z, 0x03000000); 137 | RND512Q((uint8_t*)z, y, 0x04000000); 138 | RND512Q((uint8_t*)y, z, 0x05000000); 139 | RND512Q((uint8_t*)z, y, 0x06000000); 140 | RND512Q((uint8_t*)y, z, 0x07000000); 141 | RND512Q((uint8_t*)z, y, 0x08000000); 142 | RND512Q((uint8_t*)y, Qtmp, 0x09000000); 143 | 144 | /* compute P(h+m) */ 145 | RND512P((uint8_t*)Ptmp, y, 0x00000000); 146 | RND512P((uint8_t*)y, z, 0x00000001); 147 | RND512P((uint8_t*)z, y, 0x00000002); 148 | RND512P((uint8_t*)y, z, 0x00000003); 149 | RND512P((uint8_t*)z, y, 0x00000004); 150 | RND512P((uint8_t*)y, z, 0x00000005); 151 | RND512P((uint8_t*)z, y, 0x00000006); 152 | RND512P((uint8_t*)y, z, 0x00000007); 153 | RND512P((uint8_t*)z, y, 0x00000008); 154 | RND512P((uint8_t*)y, Ptmp, 0x00000009); 155 | 156 | /* compute P(h+m) + Q(m) + h */ 157 | for (i = 0; i < 2*COLS512; i++) { 158 | h[i] ^= Ptmp[i]^Qtmp[i]; 159 | } 160 | } 161 | 162 | 163 | /* digest up to msglen bytes of input (full blocks only) */ 164 | static void Transform(hashState *ctx, 165 | const uint8_t *input, 166 | int msglen) { 167 | 168 | /* digest message, one block at a time */ 169 | for (; msglen >= SIZE512; 170 | msglen -= SIZE512, input += SIZE512) { 171 | F512(ctx->chaining,(uint32_t*)input); 172 | 173 | /* increment block counter */ 174 | ctx->block_counter1++; 175 | if (ctx->block_counter1 == 0) ctx->block_counter2++; 176 | } 177 | } 178 | 179 | /* given state h, do h <- P(h)+h */ 180 | static void OutputTransformation(hashState *ctx) { 181 | int j; 182 | uint32_t temp[2*COLS512]; 183 | uint32_t y[2*COLS512]; 184 | uint32_t z[2*COLS512]; 185 | 186 | 187 | 188 | for (j = 0; j < 2*COLS512; j++) { 189 | temp[j] = ctx->chaining[j]; 190 | } 191 | RND512P((uint8_t*)temp, y, 0x00000000); 192 | RND512P((uint8_t*)y, z, 0x00000001); 193 | RND512P((uint8_t*)z, y, 0x00000002); 194 | RND512P((uint8_t*)y, z, 0x00000003); 195 | RND512P((uint8_t*)z, y, 0x00000004); 196 | RND512P((uint8_t*)y, z, 0x00000005); 197 | RND512P((uint8_t*)z, y, 0x00000006); 198 | RND512P((uint8_t*)y, z, 0x00000007); 199 | RND512P((uint8_t*)z, y, 0x00000008); 200 | RND512P((uint8_t*)y, temp, 0x00000009); 201 | for (j = 0; j < 2*COLS512; j++) { 202 | ctx->chaining[j] ^= temp[j]; 203 | } 204 | } 205 | 206 | /* initialise context */ 207 | static void Init(hashState* ctx) { 208 | /* allocate memory for state and data buffer */ 209 | 210 | for(size_t i = 0; i < (SIZE512/sizeof(uint32_t)); i++) 211 | { 212 | ctx->chaining[i] = 0; 213 | } 214 | 215 | /* set initial value */ 216 | ctx->chaining[2*COLS512-1] = u32BIG((uint32_t)HASH_BIT_LEN); 217 | 218 | /* set other variables */ 219 | ctx->buf_ptr = 0; 220 | ctx->block_counter1 = 0; 221 | ctx->block_counter2 = 0; 222 | ctx->bits_in_last_byte = 0; 223 | } 224 | 225 | /* update state with databitlen bits of input */ 226 | static void Update(hashState* ctx, 227 | const BitSequence* input, 228 | DataLength databitlen) { 229 | int index = 0; 230 | int msglen = (int)(databitlen/8); 231 | int rem = (int)(databitlen%8); 232 | 233 | /* if the buffer contains data that has not yet been digested, first 234 | add data to buffer until full */ 235 | if (ctx->buf_ptr) { 236 | while (ctx->buf_ptr < SIZE512 && index < msglen) { 237 | ctx->buffer[(int)ctx->buf_ptr++] = input[index++]; 238 | } 239 | if (ctx->buf_ptr < SIZE512) { 240 | /* buffer still not full, return */ 241 | if (rem) { 242 | ctx->bits_in_last_byte = rem; 243 | ctx->buffer[(int)ctx->buf_ptr++] = input[index]; 244 | } 245 | return; 246 | } 247 | 248 | /* digest buffer */ 249 | ctx->buf_ptr = 0; 250 | Transform(ctx, ctx->buffer, SIZE512); 251 | } 252 | 253 | /* digest bulk of message */ 254 | Transform(ctx, input+index, msglen-index); 255 | index += ((msglen-index)/SIZE512)*SIZE512; 256 | 257 | /* store remaining data in buffer */ 258 | while (index < msglen) { 259 | ctx->buffer[(int)ctx->buf_ptr++] = input[index++]; 260 | } 261 | 262 | /* if non-integral number of bytes have been supplied, store 263 | remaining bits in last byte, together with information about 264 | number of bits */ 265 | if (rem) { 266 | ctx->bits_in_last_byte = rem; 267 | ctx->buffer[(int)ctx->buf_ptr++] = input[index]; 268 | } 269 | } 270 | 271 | #define BILB ctx->bits_in_last_byte 272 | 273 | /* finalise: process remaining data (including padding), perform 274 | output transformation, and write hash result to 'output' */ 275 | static void Final(hashState* ctx, 276 | BitSequence* output) { 277 | int i, j = 0, hashbytelen = HASH_BIT_LEN/8; 278 | uint8_t *s = (BitSequence*)ctx->chaining; 279 | 280 | /* pad with '1'-bit and first few '0'-bits */ 281 | if (BILB) { 282 | ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB); 284 | BILB = 0; 285 | } 286 | else ctx->buffer[(int)ctx->buf_ptr++] = 0x80; 287 | 288 | /* pad with '0'-bits */ 289 | if (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) { 290 | /* padding requires two blocks */ 291 | while (ctx->buf_ptr < SIZE512) { 292 | ctx->buffer[(int)ctx->buf_ptr++] = 0; 293 | } 294 | /* digest first padding block */ 295 | Transform(ctx, ctx->buffer, SIZE512); 296 | ctx->buf_ptr = 0; 297 | } 298 | while (ctx->buf_ptr < SIZE512-LENGTHFIELDLEN) { 299 | ctx->buffer[(int)ctx->buf_ptr++] = 0; 300 | } 301 | 302 | /* length padding */ 303 | ctx->block_counter1++; 304 | if (ctx->block_counter1 == 0) ctx->block_counter2++; 305 | ctx->buf_ptr = SIZE512; 306 | 307 | while (ctx->buf_ptr > SIZE512-(int)sizeof(uint32_t)) { 308 | ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter1; 309 | ctx->block_counter1 >>= 8; 310 | } 311 | while (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) { 312 | ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter2; 313 | ctx->block_counter2 >>= 8; 314 | } 315 | /* digest final padding block */ 316 | Transform(ctx, ctx->buffer, SIZE512); 317 | /* perform output transformation */ 318 | OutputTransformation(ctx); 319 | 320 | /* store hash result in output */ 321 | for (i = SIZE512-hashbytelen; i < SIZE512; i++,j++) { 322 | output[j] = s[i]; 323 | } 324 | 325 | /* zeroise relevant variables and deallocate memory */ 326 | for (i = 0; i < COLS512; i++) { 327 | ctx->chaining[i] = 0; 328 | } 329 | for (i = 0; i < SIZE512; i++) { 330 | ctx->buffer[i] = 0; 331 | } 332 | } 333 | 334 | /* hash bit sequence */ 335 | void groestl(const BitSequence* data, 336 | DataLength databitlen, 337 | BitSequence* hashval) { 338 | 339 | hashState context; 340 | 341 | /* initialise */ 342 | Init(&context); 343 | 344 | 345 | /* process message */ 346 | Update(&context, data, databitlen); 347 | 348 | /* finalise */ 349 | Final(&context, hashval); 350 | } 351 | /* 352 | static int crypto_hash(unsigned char *out, 353 | const unsigned char *in, 354 | unsigned long long len) 355 | { 356 | groestl(in, 8*len, out); 357 | return 0; 358 | } 359 | 360 | */ 361 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/blake256.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2017, The Monero Project 2 | // 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are 6 | // permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 | // of conditions and the following disclaimer in the documentation and/or other 13 | // materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its contributors may be 16 | // used to endorse or promote products derived from this software without specific 17 | // prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 20 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 | // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 | // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | // 29 | 30 | /* 31 | * The blake256_* and blake224_* functions are largely copied from 32 | * blake256_light.c and blake224_light.c from the BLAKE website: 33 | * 34 | * http://131002.net/blake/ 35 | * 36 | * The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224. 37 | * HMAC is specified by RFC 2104. 38 | */ 39 | 40 | #include 41 | #include 42 | #include 43 | #include "blake256.h" 44 | 45 | #define U8TO32(p) \ 46 | (((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \ 47 | ((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) )) 48 | #define U32TO8(p, v) \ 49 | (p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \ 50 | (p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) ); 51 | 52 | const uint8_t sigma[][16] = { 53 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, 54 | {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, 55 | {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, 56 | { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}, 57 | { 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13}, 58 | { 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9}, 59 | {12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11}, 60 | {13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10}, 61 | { 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5}, 62 | {10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0}, 63 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, 64 | {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, 65 | {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, 66 | { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8} 67 | }; 68 | 69 | const uint32_t cst[16] = { 70 | 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 71 | 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, 72 | 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 73 | 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917 74 | }; 75 | 76 | static const uint8_t padding[] = { 77 | 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, 78 | 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 79 | }; 80 | 81 | 82 | void blake256_compress(state *S, const uint8_t *block) { 83 | uint32_t v[16], m[16], i; 84 | 85 | #define ROT(x,n) (((x)<<(32-n))|((x)>>(n))) 86 | #define G(a,b,c,d,e) \ 87 | v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \ 88 | v[d] = ROT(v[d] ^ v[a],16); \ 89 | v[c] += v[d]; \ 90 | v[b] = ROT(v[b] ^ v[c],12); \ 91 | v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \ 92 | v[d] = ROT(v[d] ^ v[a], 8); \ 93 | v[c] += v[d]; \ 94 | v[b] = ROT(v[b] ^ v[c], 7); 95 | 96 | for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4); 97 | for (i = 0; i < 8; ++i) v[i] = S->h[i]; 98 | v[ 8] = S->s[0] ^ 0x243F6A88; 99 | v[ 9] = S->s[1] ^ 0x85A308D3; 100 | v[10] = S->s[2] ^ 0x13198A2E; 101 | v[11] = S->s[3] ^ 0x03707344; 102 | v[12] = 0xA4093822; 103 | v[13] = 0x299F31D0; 104 | v[14] = 0x082EFA98; 105 | v[15] = 0xEC4E6C89; 106 | 107 | if (S->nullt == 0) { 108 | v[12] ^= S->t[0]; 109 | v[13] ^= S->t[0]; 110 | v[14] ^= S->t[1]; 111 | v[15] ^= S->t[1]; 112 | } 113 | 114 | for (i = 0; i < 14; ++i) { 115 | G(0, 4, 8, 12, 0); 116 | G(1, 5, 9, 13, 2); 117 | G(2, 6, 10, 14, 4); 118 | G(3, 7, 11, 15, 6); 119 | G(3, 4, 9, 14, 14); 120 | G(2, 7, 8, 13, 12); 121 | G(0, 5, 10, 15, 8); 122 | G(1, 6, 11, 12, 10); 123 | } 124 | 125 | for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i]; 126 | for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4]; 127 | } 128 | 129 | void blake256_init(state *S) { 130 | S->h[0] = 0x6A09E667; 131 | S->h[1] = 0xBB67AE85; 132 | S->h[2] = 0x3C6EF372; 133 | S->h[3] = 0xA54FF53A; 134 | S->h[4] = 0x510E527F; 135 | S->h[5] = 0x9B05688C; 136 | S->h[6] = 0x1F83D9AB; 137 | S->h[7] = 0x5BE0CD19; 138 | S->t[0] = S->t[1] = S->buflen = S->nullt = 0; 139 | S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; 140 | } 141 | 142 | void blake224_init(state *S) { 143 | S->h[0] = 0xC1059ED8; 144 | S->h[1] = 0x367CD507; 145 | S->h[2] = 0x3070DD17; 146 | S->h[3] = 0xF70E5939; 147 | S->h[4] = 0xFFC00B31; 148 | S->h[5] = 0x68581511; 149 | S->h[6] = 0x64F98FA7; 150 | S->h[7] = 0xBEFA4FA4; 151 | S->t[0] = S->t[1] = S->buflen = S->nullt = 0; 152 | S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; 153 | } 154 | 155 | // datalen = number of bits 156 | void blake256_update(state *S, const uint8_t *data, uint64_t datalen) { 157 | int left = S->buflen >> 3; 158 | int fill = 64 - left; 159 | 160 | if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) { 161 | memcpy((void *) (S->buf + left), (void *) data, fill); 162 | S->t[0] += 512; 163 | if (S->t[0] == 0) S->t[1]++; 164 | blake256_compress(S, S->buf); 165 | data += fill; 166 | datalen -= (uint64_t)(fill << 3); 167 | left = 0; 168 | } 169 | 170 | while (datalen >= 512) { 171 | S->t[0] += 512; 172 | if (S->t[0] == 0) S->t[1]++; 173 | blake256_compress(S, data); 174 | data += 64; 175 | datalen -= 512; 176 | } 177 | 178 | if (datalen > 0) { 179 | memcpy((void *) (S->buf + left), (void *) data, datalen >> 3); 180 | S->buflen = (int)(((uint64_t)left << 3) + datalen); 181 | } else { 182 | S->buflen = 0; 183 | } 184 | } 185 | 186 | // datalen = number of bits 187 | void blake224_update(state *S, const uint8_t *data, uint64_t datalen) { 188 | blake256_update(S, data, datalen); 189 | } 190 | 191 | void blake256_final_h(state *S, uint8_t *digest, uint8_t pa, uint8_t pb) { 192 | uint8_t msglen[8]; 193 | uint32_t lo = S->t[0] + (uint32_t)S->buflen, hi = S->t[1]; 194 | if (lo < (unsigned) S->buflen) hi++; 195 | U32TO8(msglen + 0, hi); 196 | U32TO8(msglen + 4, lo); 197 | 198 | if (S->buflen == 440) { /* one padding byte */ 199 | S->t[0] -= 8; 200 | blake256_update(S, &pa, 8); 201 | } else { 202 | if (S->buflen < 440) { /* enough space to fill the block */ 203 | if (S->buflen == 0) S->nullt = 1; 204 | S->t[0] -= 440 - (uint32_t)S->buflen; 205 | blake256_update(S, padding, 440 - (uint32_t)S->buflen); 206 | } else { /* need 2 compressions */ 207 | S->t[0] -= 512 - (uint32_t)S->buflen; 208 | blake256_update(S, padding, 512 - (uint32_t)S->buflen); 209 | S->t[0] -= 440; 210 | blake256_update(S, padding + 1, 440); 211 | S->nullt = 1; 212 | } 213 | blake256_update(S, &pb, 8); 214 | S->t[0] -= 8; 215 | } 216 | S->t[0] -= 64; 217 | blake256_update(S, msglen, 64); 218 | 219 | U32TO8(digest + 0, S->h[0]); 220 | U32TO8(digest + 4, S->h[1]); 221 | U32TO8(digest + 8, S->h[2]); 222 | U32TO8(digest + 12, S->h[3]); 223 | U32TO8(digest + 16, S->h[4]); 224 | U32TO8(digest + 20, S->h[5]); 225 | U32TO8(digest + 24, S->h[6]); 226 | U32TO8(digest + 28, S->h[7]); 227 | } 228 | 229 | void blake256_final(state *S, uint8_t *digest) { 230 | blake256_final_h(S, digest, 0x81, 0x01); 231 | } 232 | 233 | void blake224_final(state *S, uint8_t *digest) { 234 | blake256_final_h(S, digest, 0x80, 0x00); 235 | } 236 | 237 | // inlen = number of bytes 238 | void blake256_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) { 239 | state S; 240 | blake256_init(&S); 241 | blake256_update(&S, in, inlen * 8); 242 | blake256_final(&S, out); 243 | } 244 | 245 | // inlen = number of bytes 246 | void blake224_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) { 247 | state S; 248 | blake224_init(&S); 249 | blake224_update(&S, in, inlen * 8); 250 | blake224_final(&S, out); 251 | } 252 | 253 | // keylen = number of bytes 254 | void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) { 255 | const uint8_t *key = _key; 256 | uint8_t keyhash[32]; 257 | uint8_t pad[64]; 258 | uint64_t i; 259 | 260 | if (keylen > 64) { 261 | blake256_hash(keyhash, key, keylen); 262 | key = keyhash; 263 | keylen = 32; 264 | } 265 | 266 | blake256_init(&S->inner); 267 | memset(pad, 0x36, 64); 268 | for (i = 0; i < keylen; ++i) { 269 | pad[i] ^= key[i]; 270 | } 271 | blake256_update(&S->inner, pad, 512); 272 | 273 | blake256_init(&S->outer); 274 | memset(pad, 0x5c, 64); 275 | for (i = 0; i < keylen; ++i) { 276 | pad[i] ^= key[i]; 277 | } 278 | blake256_update(&S->outer, pad, 512); 279 | 280 | memset(keyhash, 0, 32); 281 | } 282 | 283 | // keylen = number of bytes 284 | void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) { 285 | const uint8_t *key = _key; 286 | uint8_t keyhash[32]; 287 | uint8_t pad[64]; 288 | uint64_t i; 289 | 290 | if (keylen > 64) { 291 | blake256_hash(keyhash, key, keylen); 292 | key = keyhash; 293 | keylen = 28; 294 | } 295 | 296 | blake224_init(&S->inner); 297 | memset(pad, 0x36, 64); 298 | for (i = 0; i < keylen; ++i) { 299 | pad[i] ^= key[i]; 300 | } 301 | blake224_update(&S->inner, pad, 512); 302 | 303 | blake224_init(&S->outer); 304 | memset(pad, 0x5c, 64); 305 | for (i = 0; i < keylen; ++i) { 306 | pad[i] ^= key[i]; 307 | } 308 | blake224_update(&S->outer, pad, 512); 309 | 310 | memset(keyhash, 0, 32); 311 | } 312 | 313 | // datalen = number of bits 314 | void hmac_blake256_update(hmac_state *S, const uint8_t *data, uint64_t datalen) { 315 | // update the inner state 316 | blake256_update(&S->inner, data, datalen); 317 | } 318 | 319 | // datalen = number of bits 320 | void hmac_blake224_update(hmac_state *S, const uint8_t *data, uint64_t datalen) { 321 | // update the inner state 322 | blake224_update(&S->inner, data, datalen); 323 | } 324 | 325 | void hmac_blake256_final(hmac_state *S, uint8_t *digest) { 326 | uint8_t ihash[32]; 327 | blake256_final(&S->inner, ihash); 328 | blake256_update(&S->outer, ihash, 256); 329 | blake256_final(&S->outer, digest); 330 | memset(ihash, 0, 32); 331 | } 332 | 333 | void hmac_blake224_final(hmac_state *S, uint8_t *digest) { 334 | uint8_t ihash[32]; 335 | blake224_final(&S->inner, ihash); 336 | blake224_update(&S->outer, ihash, 224); 337 | blake224_final(&S->outer, digest); 338 | memset(ihash, 0, 32); 339 | } 340 | 341 | // keylen = number of bytes; inlen = number of bytes 342 | void hmac_blake256_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) { 343 | hmac_state S; 344 | hmac_blake256_init(&S, key, keylen); 345 | hmac_blake256_update(&S, in, inlen * 8); 346 | hmac_blake256_final(&S, out); 347 | } 348 | 349 | // keylen = number of bytes; inlen = number of bytes 350 | void hmac_blake224_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) { 351 | hmac_state S; 352 | hmac_blake224_init(&S, key, keylen); 353 | hmac_blake224_update(&S, in, inlen * 8); 354 | hmac_blake224_final(&S, out); 355 | } 356 | -------------------------------------------------------------------------------- /MoneroKit/MoneroPoolConnection.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoneroPoolConnection.m 3 | // MoneroKit 4 | // 5 | // Created by Yury Popov on 08.12.2017. 6 | // Copyright © 2017 PhoeniX. All rights reserved. 7 | // 8 | 9 | #import "MoneroPoolConnection.h" 10 | #import "MoneroBackend.h" 11 | #import "NSData+hex.h" 12 | 13 | #import 14 | #import 15 | #import 16 | 17 | static const char agentString[] = "MoneroKit/1.0"; 18 | 19 | @interface MoneroPoolConnection () 20 | @property (atomic, strong) NSString *host; 21 | @property (atomic, strong) NSString *user; 22 | @property (atomic, strong) NSString *password; 23 | @property (atomic, strong) NSInputStream *input; 24 | @property (atomic, strong) NSOutputStream *output; 25 | @property (atomic, strong) NSMutableData *inBuffer; 26 | @property (atomic, strong) NSMutableData *outBuffer; 27 | @property (atomic, strong) NSString *workerId; 28 | @property (atomic, strong) NSMutableDictionary *callbacks; 29 | @property (atomic) uint16_t port; 30 | @property (atomic) uint32_t seq; 31 | @property (atomic) BOOL ssl; 32 | @property (atomic) NSTimer *pingTimer; 33 | @end 34 | 35 | @implementation MoneroPoolConnection 36 | 37 | + (instancetype)connectionWithHost:(NSString*)host port:(NSInteger)port ssl:(BOOL)ssl walletAddress:(NSString*)walletAddress password:(NSString*)password { 38 | return [[self alloc] initWithHost:host port:port ssl:ssl walletAddress:walletAddress password:password]; 39 | } 40 | 41 | - (instancetype)initWithHost:(NSString*)host port:(NSInteger)port ssl:(BOOL)ssl walletAddress:(NSString*)walletAddress password:(NSString*)password { 42 | if (self = [super init]) { 43 | self.runLoop = [NSRunLoop mainRunLoop]; 44 | self.host = host; 45 | self.user = walletAddress; 46 | self.password = password; 47 | self.port = (uint16_t)port; 48 | self.ssl = ssl; 49 | self.outBuffer = [NSMutableData new]; 50 | self.inBuffer = [NSMutableData new]; 51 | self.workerId = nil; 52 | self.callbacks = [NSMutableDictionary new]; 53 | } 54 | return self; 55 | } 56 | 57 | - (void)connect { 58 | NSInputStream *ins; NSOutputStream *outs; 59 | [NSStream getStreamsToHostWithName:_host port:_port inputStream:&ins outputStream:&outs]; 60 | 61 | [ins setProperty:NSStreamNetworkServiceTypeBackground forKey:NSStreamNetworkServiceType]; 62 | [outs setProperty:NSStreamNetworkServiceTypeBackground forKey:NSStreamNetworkServiceType]; 63 | 64 | if (self.ssl) { 65 | NSDictionary *sets = @{ 66 | (__bridge NSString*)kCFStreamSSLValidatesCertificateChain: @NO 67 | }; 68 | [ins setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey]; 69 | [outs setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey]; 70 | [ins setProperty:sets forKey:(__bridge NSString*)kCFStreamPropertySSLSettings]; 71 | [outs setProperty:sets forKey:(__bridge NSString*)kCFStreamPropertySSLSettings]; 72 | } 73 | 74 | [ins setDelegate:self]; 75 | [outs setDelegate:self]; 76 | [ins scheduleInRunLoop:_runLoop forMode:NSRunLoopCommonModes]; 77 | [outs scheduleInRunLoop:_runLoop forMode:NSRunLoopCommonModes]; 78 | [(self.input = ins) open]; 79 | [(self.output = outs) open]; 80 | 81 | [self.outBuffer setLength:0]; 82 | [self.inBuffer setLength:0]; 83 | [self.callbacks removeAllObjects]; 84 | self.seq = 0; 85 | __weak __typeof__(self) wself = self; 86 | [self sendCommand:@"login" withOptions:@{@"login":_user, @"pass":_password, @"agent":@(agentString)} callback:^(NSError *error, NSDictionary* result) { 87 | __strong __typeof__(wself) self = wself; 88 | if (!self) return; 89 | self.workerId = [[result objectForKey:@"id"] copy]; 90 | [self handleJob:[result objectForKey:@"job"]]; 91 | [self heartbeat]; 92 | }]; 93 | } 94 | 95 | - (void)heartbeat { 96 | [self.pingTimer invalidate]; 97 | self.pingTimer = [NSTimer timerWithTimeInterval:30 target:self selector:@selector(sendHeartbeat) userInfo:nil repeats:NO]; 98 | [_runLoop addTimer:self.pingTimer forMode:NSRunLoopCommonModes]; 99 | } 100 | 101 | - (void)sendHeartbeat { 102 | if (!self.workerId) return; 103 | __weak __typeof__(self) wself = self; 104 | [self sendCommand:@"getjob" withOptions:@{@"id": self.workerId} callback:^(NSError *error, NSDictionary* result) { 105 | __strong __typeof__(wself) self = wself; 106 | if (!self) return; 107 | [self handleJob:result]; 108 | }]; 109 | [self heartbeat]; 110 | } 111 | 112 | - (void)close { 113 | [self.pingTimer invalidate]; 114 | self.pingTimer = nil; 115 | [self.input removeFromRunLoop:self.runLoop forMode:NSRunLoopCommonModes]; 116 | [self.output removeFromRunLoop:self.runLoop forMode:NSRunLoopCommonModes]; 117 | [self.input close]; 118 | [self.output close]; 119 | self.input = nil; 120 | self.output = nil; 121 | [self.outBuffer setLength:0]; 122 | [self.inBuffer setLength:0]; 123 | [self.callbacks removeAllObjects]; 124 | } 125 | 126 | inline static uint64_t t32_to_t64(uint32_t t) { return 0xFFFFFFFFFFFFFFFFULL / (0xFFFFFFFFULL / ((uint64_t)t)); } 127 | 128 | - (void)handleJob:(NSDictionary*)dict { 129 | id delegate = [self delegate]; 130 | if (!delegate) return; 131 | NSString *jid = [dict objectForKey:@"job_id"]; 132 | NSString *blobS = [dict objectForKey:@"blob"]; 133 | NSString *targetS = [dict objectForKey:@"target"]; 134 | if (![jid isKindOfClass:[NSString class]] || 135 | ![blobS isKindOfClass:[NSString class]] || 136 | ![targetS isKindOfClass:[NSString class]]) return; 137 | 138 | uint64_t height = 0; 139 | if ([[dict objectForKey:@"height"] isKindOfClass:[NSNumber class]]) 140 | height = [(NSNumber*)[dict objectForKey:@"height"] unsignedLongLongValue]; 141 | 142 | NSData *blob = _mm_dataFromHexString(blobS); 143 | NSData *target = _mm_dataFromHexString(targetS); 144 | 145 | MoneroBackendJob *job = [MoneroBackendJob new]; 146 | [job setJobId:jid]; 147 | [job setBlob:blob]; 148 | [job setHeight:height]; 149 | if ([target length] <= 4) { 150 | uint32_t tmp = 0; 151 | [target getBytes:&tmp length:sizeof(tmp)]; 152 | [job setTarget:t32_to_t64(tmp)]; 153 | } else if ([target length] <= 8) { 154 | uint64_t tmp = 0; 155 | [target getBytes:&tmp length:sizeof(tmp)]; 156 | [job setTarget:tmp]; 157 | } else { 158 | return; 159 | } 160 | [delegate connection:self receivedNewJob:job]; 161 | } 162 | 163 | - (void)sendCommand:(NSString *)command withOptions:(NSDictionary*)options callback:(MoneroPoolConnectionCallback)callback { 164 | NSDictionary *cmd = @{ 165 | @"method": command, 166 | @"params": options, 167 | @"id": @(++_seq) 168 | }; 169 | if (callback) [self.callbacks setObject:callback forKey:@(_seq)]; 170 | [self writeJSON:cmd]; 171 | } 172 | 173 | - (void)submitShare:(const struct MoneroHash*)hash withNonce:(uint32_t)nonce forJobId:(NSString*)jobId callback:(nonnull MoneroPoolResultCallback)callback { 174 | if (!self.workerId) { 175 | callback([NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUserAuthenticationRequired userInfo:nil]); 176 | return; 177 | } 178 | NSString *hashHex = _mm_hexStringFromData([NSData dataWithBytes:hash->bytes length:sizeof(hash->bytes)]); 179 | NSString *nonceHex = _mm_hexStringFromData([NSData dataWithBytes:&nonce length:sizeof(nonce)]); 180 | [self sendCommand:@"submit" 181 | withOptions:@{ 182 | @"id": self.workerId, 183 | @"job_id": jobId, 184 | @"nonce": nonceHex, 185 | @"result": hashHex 186 | } 187 | callback:^(NSError * _Nullable error, NSDictionary * _Nullable result) { 188 | if (error) { 189 | callback(error); 190 | } else if ([[result objectForKey:@"status"] isEqual:@"OK"]) { 191 | callback(nil); 192 | } else { 193 | callback([NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnknown userInfo:result]); 194 | } 195 | [self heartbeat]; 196 | } 197 | ]; 198 | } 199 | 200 | - (void)writeJSON:(NSDictionary*)json { 201 | NSError *error = nil; 202 | NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:&error]; 203 | if (!data || error) { 204 | [self handleError:error]; 205 | return; 206 | } 207 | [self.outBuffer appendBytes:data.bytes length:data.length]; 208 | [self.outBuffer appendBytes:(char[]){'\n'} length:1]; 209 | if (self.output && self.output.streamStatus == NSStreamStatusOpen && self.output.hasSpaceAvailable) { 210 | [self processOutputBuffer]; 211 | } 212 | } 213 | 214 | - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { 215 | if (aStream == self.input) [self handleInputEvent:eventCode]; 216 | if (aStream == self.output) [self handleOutputEvent:eventCode]; 217 | } 218 | 219 | - (void)handleInputEvent:(NSStreamEvent)event { 220 | switch (event) { 221 | case NSStreamEventOpenCompleted: { 222 | CFDataRef socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)_input, kCFStreamPropertySocketNativeHandle); 223 | CFSocketNativeHandle socket; 224 | CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket); 225 | CFRelease(socketData); 226 | setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (int[]){1}, sizeof(int)); 227 | setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, (int[]){4}, sizeof(int)); 228 | setsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, (int[]){10}, sizeof(int)); 229 | setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, (int[]){2}, sizeof(int)); 230 | setsockopt(socket, IPPROTO_TCP, TCP_RXT_CONNDROPTIME, (int[]){5}, sizeof(int)); 231 | setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (int[]){1}, sizeof(int)); 232 | break; } 233 | case NSStreamEventEndEncountered: 234 | [self handleError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorNetworkConnectionLost userInfo:nil]]; 235 | break; 236 | case NSStreamEventErrorOccurred: 237 | [self handleError:self.input.streamError]; 238 | break; 239 | case NSStreamEventHasBytesAvailable: { 240 | NSMutableData *buf = [[NSMutableData alloc] initWithLength:4096]; 241 | NSInteger len = 0; 242 | while ([self.input hasBytesAvailable] && (len = [self.input read:buf.mutableBytes maxLength:buf.length]) > 0) { 243 | [self.inBuffer appendBytes:buf.bytes length:(NSUInteger)len]; 244 | } 245 | [self processInputBuffer]; 246 | break; } 247 | default: break; 248 | } 249 | } 250 | 251 | - (void)processInputBuffer { 252 | while ([self.inBuffer length] > 0) { 253 | const char *s = [self.inBuffer bytes]; 254 | const char *e = memchr(s, '\n', [self.inBuffer length]); 255 | if (e == 0) break; 256 | NSUInteger len = (NSUInteger)(e - s + 1); 257 | NSData *line = [self.inBuffer subdataWithRange:NSMakeRange(0, len)]; 258 | [self.inBuffer setData:[self.inBuffer subdataWithRange:NSMakeRange(len, [self.inBuffer length] - len)]]; 259 | id json = [NSJSONSerialization JSONObjectWithData:line options:NSJSONReadingAllowFragments error:nil]; 260 | [self processJSONMessage:json]; 261 | } 262 | } 263 | 264 | - (void)handleCommand:(NSString *)command withOptions:(NSDictionary*)options callback:(MoneroPoolConnectionCallback)callback { 265 | if ([command isEqualToString:@"job"]) { 266 | [self handleJob:options]; 267 | callback(nil, @{@"status":@"OK"}); 268 | } else { 269 | id delegate = [self delegate]; 270 | if (delegate) { 271 | [delegate connection:self receivedCommand:command withOptions:options callback:callback]; 272 | } else { 273 | callback(nil, nil); 274 | } 275 | } 276 | } 277 | 278 | - (void)processJSONMessage:(NSDictionary*)json { 279 | NSNumber *seq = [json objectForKey:@"id"]; 280 | NSString *method = [json objectForKey:@"method"]; 281 | NSDictionary *params = [json objectForKey:@"params"]; 282 | NSDictionary *result = [json objectForKey:@"result"]; 283 | NSDictionary *error = [json objectForKey:@"error"]; 284 | if ([method isKindOfClass:[NSString class]] && [params isKindOfClass:[NSDictionary class]]) { 285 | __weak __typeof__(self) wself = self; 286 | [self handleCommand:method withOptions:params callback:^(NSError *error, NSDictionary *result) { 287 | if (![seq isKindOfClass:[NSNumber class]]) return; 288 | __strong __typeof__(wself) self = wself; 289 | if (!self) return; 290 | if (result) { 291 | [self writeJSON:@{ 292 | @"id": seq, 293 | @"result": result, 294 | @"error": [NSNull null] 295 | }]; 296 | } else if (error) { 297 | NSLog(@"%@", error); 298 | } 299 | }]; 300 | } else if ([seq isKindOfClass:[NSNumber class]] && [result isKindOfClass:[NSDictionary class]]) { 301 | MoneroPoolConnectionCallback cb = [self.callbacks objectForKey:seq]; 302 | [self.callbacks removeObjectForKey:seq]; 303 | if (cb) { 304 | cb(nil, result); 305 | } else { 306 | NSLog(@"%@", json); 307 | } 308 | } else if ([seq isKindOfClass:[NSNumber class]] && [error isKindOfClass:[NSDictionary class]]) { 309 | MoneroPoolConnectionCallback cb = [self.callbacks objectForKey:seq]; 310 | [self.callbacks removeObjectForKey:seq]; 311 | if (cb) { 312 | cb( 313 | [NSError errorWithDomain:@"MoneroKitErrorDomain" 314 | code:[[error objectForKey:@"code"] integerValue] 315 | userInfo:@{ NSLocalizedDescriptionKey: [error objectForKey:@"message"] }], 316 | nil 317 | ); 318 | } else { 319 | NSLog(@"%@", json); 320 | } 321 | } else { 322 | NSLog(@"%@", json); 323 | } 324 | } 325 | 326 | - (void)processOutputBuffer { 327 | NSUInteger buflen = self.outBuffer.length; 328 | if (buflen == 0) return; 329 | NSInteger len = [self.output write:[self.outBuffer bytes] maxLength:buflen]; 330 | if (len > 0) { 331 | [self.outBuffer setData:[self.outBuffer subdataWithRange:NSMakeRange((NSUInteger)len, MIN(buflen - (NSUInteger)len, (NSUInteger)0))]]; 332 | } 333 | } 334 | 335 | - (void)handleOutputEvent:(NSStreamEvent)event { 336 | switch (event) { 337 | case NSStreamEventEndEncountered: 338 | [self handleError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorNetworkConnectionLost userInfo:nil]]; 339 | break; 340 | case NSStreamEventErrorOccurred: 341 | [self handleError:self.output.streamError]; 342 | break; 343 | case NSStreamEventHasSpaceAvailable: 344 | [self processOutputBuffer]; 345 | break; 346 | default: break; 347 | } 348 | } 349 | 350 | - (void)handleError:(NSError*)error { 351 | [self close]; 352 | id delegate = [self delegate]; 353 | [delegate connection:self error:error]; 354 | } 355 | 356 | @end 357 | -------------------------------------------------------------------------------- /MoneroKit/CPU/crypto/variant4_random_math.h: -------------------------------------------------------------------------------- 1 | #ifndef VARIANT4_RANDOM_MATH_H 2 | #define VARIANT4_RANDOM_MATH_H 3 | 4 | // Register size can be configured to either 32 bit (uint32_t) or 64 bit (uint64_t) 5 | typedef uint32_t v4_reg; 6 | 7 | enum V4_Settings 8 | { 9 | // Generate code with minimal theoretical latency = 45 cycles, which is equivalent to 15 multiplications 10 | TOTAL_LATENCY = 15 * 3, 11 | 12 | // Always generate at least 60 instructions 13 | NUM_INSTRUCTIONS_MIN = 60, 14 | 15 | // Never generate more than 70 instructions (final RET instruction doesn't count here) 16 | NUM_INSTRUCTIONS_MAX = 70, 17 | 18 | // Available ALUs for MUL 19 | // Modern CPUs typically have only 1 ALU which can do multiplications 20 | ALU_COUNT_MUL = 1, 21 | 22 | // Total available ALUs 23 | // Modern CPUs have 4 ALUs, but we use only 3 because random math executes together with other main loop code 24 | ALU_COUNT = 3, 25 | }; 26 | 27 | enum V4_InstructionList 28 | { 29 | MUL, // a*b 30 | ADD, // a+b + C, C is an unsigned 32-bit constant 31 | SUB, // a-b 32 | ROR, // rotate right "a" by "b & 31" bits 33 | ROL, // rotate left "a" by "b & 31" bits 34 | XOR, // a^b 35 | RET, // finish execution 36 | V4_INSTRUCTION_COUNT = RET, 37 | }; 38 | 39 | // V4_InstructionDefinition is used to generate code from random data 40 | // Every random sequence of bytes is a valid code 41 | // 42 | // There are 9 registers in total: 43 | // - 4 variable registers 44 | // - 5 constant registers initialized from loop variables 45 | // This is why dst_index is 2 bits 46 | enum V4_InstructionDefinition 47 | { 48 | V4_OPCODE_BITS = 3, 49 | V4_DST_INDEX_BITS = 2, 50 | V4_SRC_INDEX_BITS = 3, 51 | }; 52 | 53 | struct V4_Instruction 54 | { 55 | uint8_t opcode; 56 | uint8_t dst_index; 57 | uint8_t src_index; 58 | uint32_t C; 59 | }; 60 | 61 | #ifndef FORCEINLINE 62 | #if defined(__GNUC__) 63 | #define FORCEINLINE __attribute__((always_inline)) inline 64 | #elif defined(_MSC_VER) 65 | #define FORCEINLINE __forceinline 66 | #else 67 | #define FORCEINLINE inline 68 | #endif 69 | #endif 70 | 71 | #ifndef UNREACHABLE_CODE 72 | #if defined(__GNUC__) 73 | #define UNREACHABLE_CODE __builtin_unreachable() 74 | #elif defined(_MSC_VER) 75 | #define UNREACHABLE_CODE __assume(false) 76 | #else 77 | #define UNREACHABLE_CODE 78 | #endif 79 | #endif 80 | 81 | // Random math interpreter's loop is fully unrolled and inlined to achieve 100% branch prediction on CPU: 82 | // every switch-case will point to the same destination on every iteration of Cryptonight main loop 83 | // 84 | // This is about as fast as it can get without using low-level machine code generation 85 | static FORCEINLINE void v4_random_math(const struct V4_Instruction* code, v4_reg* r) 86 | { 87 | enum 88 | { 89 | REG_BITS = sizeof(v4_reg) * 8, 90 | }; 91 | 92 | #define V4_EXEC(i) \ 93 | { \ 94 | const struct V4_Instruction* op = code + i; \ 95 | const v4_reg src = r[op->src_index]; \ 96 | v4_reg* dst = r + op->dst_index; \ 97 | switch (op->opcode) \ 98 | { \ 99 | case MUL: \ 100 | *dst *= src; \ 101 | break; \ 102 | case ADD: \ 103 | *dst += src + op->C; \ 104 | break; \ 105 | case SUB: \ 106 | *dst -= src; \ 107 | break; \ 108 | case ROR: \ 109 | { \ 110 | const uint32_t shift = src % REG_BITS; \ 111 | *dst = (*dst >> shift) | (*dst << ((REG_BITS - shift) % REG_BITS)); \ 112 | } \ 113 | break; \ 114 | case ROL: \ 115 | { \ 116 | const uint32_t shift = src % REG_BITS; \ 117 | *dst = (*dst << shift) | (*dst >> ((REG_BITS - shift) % REG_BITS)); \ 118 | } \ 119 | break; \ 120 | case XOR: \ 121 | *dst ^= src; \ 122 | break; \ 123 | case RET: \ 124 | return; \ 125 | default: \ 126 | UNREACHABLE_CODE; \ 127 | break; \ 128 | } \ 129 | } 130 | 131 | #define V4_EXEC_10(j) \ 132 | V4_EXEC(j + 0) \ 133 | V4_EXEC(j + 1) \ 134 | V4_EXEC(j + 2) \ 135 | V4_EXEC(j + 3) \ 136 | V4_EXEC(j + 4) \ 137 | V4_EXEC(j + 5) \ 138 | V4_EXEC(j + 6) \ 139 | V4_EXEC(j + 7) \ 140 | V4_EXEC(j + 8) \ 141 | V4_EXEC(j + 9) 142 | 143 | // Generated program can have 60 + a few more (usually 2-3) instructions to achieve required latency 144 | // I've checked all block heights < 10,000,000 and here is the distribution of program sizes: 145 | // 146 | // 60 27960 147 | // 61 105054 148 | // 62 2452759 149 | // 63 5115997 150 | // 64 1022269 151 | // 65 1109635 152 | // 66 153145 153 | // 67 8550 154 | // 68 4529 155 | // 69 102 156 | 157 | // Unroll 70 instructions here 158 | V4_EXEC_10(0); // instructions 0-9 159 | V4_EXEC_10(10); // instructions 10-19 160 | V4_EXEC_10(20); // instructions 20-29 161 | V4_EXEC_10(30); // instructions 30-39 162 | V4_EXEC_10(40); // instructions 40-49 163 | V4_EXEC_10(50); // instructions 50-59 164 | V4_EXEC_10(60); // instructions 60-69 165 | 166 | #undef V4_EXEC_10 167 | #undef V4_EXEC 168 | } 169 | 170 | // If we don't have enough data available, generate more 171 | static FORCEINLINE void check_data(size_t* data_index, const size_t bytes_needed, int8_t* data, const size_t data_size) 172 | { 173 | if (*data_index + bytes_needed > data_size) 174 | { 175 | hash_extra_blake(data, data_size, (char*) data); 176 | *data_index = 0; 177 | } 178 | } 179 | 180 | // Generates as many random math operations as possible with given latency and ALU restrictions 181 | // "code" array must have space for NUM_INSTRUCTIONS_MAX+1 instructions 182 | static inline int v4_random_math_init(struct V4_Instruction* code, const uint64_t height) 183 | { 184 | // MUL is 3 cycles, 3-way addition and rotations are 2 cycles, SUB/XOR are 1 cycle 185 | // These latencies match real-life instruction latencies for Intel CPUs starting from Sandy Bridge and up to Skylake/Coffee lake 186 | // 187 | // AMD Ryzen has the same latencies except 1-cycle ROR/ROL, so it'll be a bit faster than Intel Sandy Bridge and newer processors 188 | // Surprisingly, Intel Nehalem also has 1-cycle ROR/ROL, so it'll also be faster than Intel Sandy Bridge and newer processors 189 | // AMD Bulldozer has 4 cycles latency for MUL (slower than Intel) and 1 cycle for ROR/ROL (faster than Intel), so average performance will be the same 190 | // Source: https://www.agner.org/optimize/instruction_tables.pdf 191 | const int op_latency[V4_INSTRUCTION_COUNT] = { 3, 2, 1, 2, 2, 1 }; 192 | 193 | // Instruction latencies for theoretical ASIC implementation 194 | const int asic_op_latency[V4_INSTRUCTION_COUNT] = { 3, 1, 1, 1, 1, 1 }; 195 | 196 | // Available ALUs for each instruction 197 | const int op_ALUs[V4_INSTRUCTION_COUNT] = { ALU_COUNT_MUL, ALU_COUNT, ALU_COUNT, ALU_COUNT, ALU_COUNT, ALU_COUNT }; 198 | 199 | int8_t data[32]; 200 | memset(data, 0, sizeof(data)); 201 | uint64_t tmp = (height); 202 | memcpy(data, &tmp, sizeof(uint64_t)); 203 | data[20] = -38; // change seed 204 | 205 | // Set data_index past the last byte in data 206 | // to trigger full data update with blake hash 207 | // before we start using it 208 | size_t data_index = sizeof(data); 209 | 210 | int code_size; 211 | 212 | // There is a small chance (1.8%) that register R8 won't be used in the generated program 213 | // So we keep track of it and try again if it's not used 214 | bool r8_used; 215 | do { 216 | int latency[9]; 217 | int asic_latency[9]; 218 | 219 | // Tracks previous instruction and value of the source operand for registers R0-R3 throughout code execution 220 | // byte 0: current value of the destination register 221 | // byte 1: instruction opcode 222 | // byte 2: current value of the source register 223 | // 224 | // Registers R4-R8 are constant and are treated as having the same value because when we do 225 | // the same operation twice with two constant source registers, it can be optimized into a single operation 226 | uint32_t inst_data[9] = { 0, 1, 2, 3, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF }; 227 | 228 | bool alu_busy[TOTAL_LATENCY + 1][ALU_COUNT]; 229 | bool is_rotation[V4_INSTRUCTION_COUNT]; 230 | bool rotated[4]; 231 | int rotate_count = 0; 232 | 233 | memset(latency, 0, sizeof(latency)); 234 | memset(asic_latency, 0, sizeof(asic_latency)); 235 | memset(alu_busy, 0, sizeof(alu_busy)); 236 | memset(is_rotation, 0, sizeof(is_rotation)); 237 | memset(rotated, 0, sizeof(rotated)); 238 | is_rotation[ROR] = true; 239 | is_rotation[ROL] = true; 240 | 241 | int num_retries = 0; 242 | code_size = 0; 243 | 244 | int total_iterations = 0; 245 | r8_used = false; 246 | 247 | // Generate random code to achieve minimal required latency for our abstract CPU 248 | // Try to get this latency for all 4 registers 249 | while (((latency[0] < TOTAL_LATENCY) || (latency[1] < TOTAL_LATENCY) || (latency[2] < TOTAL_LATENCY) || (latency[3] < TOTAL_LATENCY)) && (num_retries < 64)) 250 | { 251 | // Fail-safe to guarantee loop termination 252 | ++total_iterations; 253 | if (total_iterations > 256) 254 | break; 255 | 256 | check_data(&data_index, 1, data, sizeof(data)); 257 | 258 | const uint8_t c = ((uint8_t*)data)[data_index++]; 259 | 260 | // MUL = opcodes 0-2 261 | // ADD = opcode 3 262 | // SUB = opcode 4 263 | // ROR/ROL = opcode 5, shift direction is selected randomly 264 | // XOR = opcodes 6-7 265 | uint8_t opcode = c & ((1 << V4_OPCODE_BITS) - 1); 266 | if (opcode == 5) 267 | { 268 | check_data(&data_index, 1, data, sizeof(data)); 269 | opcode = (data[data_index++] >= 0) ? ROR : ROL; 270 | } 271 | else if (opcode >= 6) 272 | { 273 | opcode = XOR; 274 | } 275 | else 276 | { 277 | opcode = (opcode <= 2) ? MUL : (opcode - 2); 278 | } 279 | 280 | uint8_t dst_index = (c >> V4_OPCODE_BITS) & ((1 << V4_DST_INDEX_BITS) - 1); 281 | uint8_t src_index = (c >> (V4_OPCODE_BITS + V4_DST_INDEX_BITS)) & ((1 << V4_SRC_INDEX_BITS) - 1); 282 | 283 | const int a = dst_index; 284 | int b = src_index; 285 | 286 | // Don't do ADD/SUB/XOR with the same register 287 | if (((opcode == ADD) || (opcode == SUB) || (opcode == XOR)) && (a == b)) 288 | { 289 | // Use register R8 as source instead 290 | b = 8; 291 | src_index = 8; 292 | } 293 | 294 | // Don't do rotation with the same destination twice because it's equal to a single rotation 295 | if (is_rotation[opcode] && rotated[a]) 296 | { 297 | continue; 298 | } 299 | 300 | // Don't do the same instruction (except MUL) with the same source value twice because all other cases can be optimized: 301 | // 2xADD(a, b, C) = ADD(a, b*2, C1+C2), same for SUB and rotations 302 | // 2xXOR(a, b) = NOP 303 | if ((opcode != MUL) && ((inst_data[a] & 0xFFFF00) == (opcode << 8) + ((inst_data[b] & 255) << 16))) 304 | { 305 | continue; 306 | } 307 | 308 | // Find which ALU is available (and when) for this instruction 309 | int next_latency = (latency[a] > latency[b]) ? latency[a] : latency[b]; 310 | int alu_index = -1; 311 | while (next_latency < TOTAL_LATENCY) 312 | { 313 | for (int i = op_ALUs[opcode] - 1; i >= 0; --i) 314 | { 315 | if (!alu_busy[next_latency][i]) 316 | { 317 | // ADD is implemented as two 1-cycle instructions on a real CPU, so do an additional availability check 318 | if ((opcode == ADD) && alu_busy[next_latency + 1][i]) 319 | { 320 | continue; 321 | } 322 | 323 | // Rotation can only start when previous rotation is finished, so do an additional availability check 324 | if (is_rotation[opcode] && (next_latency < rotate_count * op_latency[opcode])) 325 | { 326 | continue; 327 | } 328 | 329 | alu_index = i; 330 | break; 331 | } 332 | } 333 | if (alu_index >= 0) 334 | { 335 | break; 336 | } 337 | ++next_latency; 338 | } 339 | 340 | // Don't generate instructions that leave some register unchanged for more than 7 cycles 341 | if (next_latency > latency[a] + 7) 342 | { 343 | continue; 344 | } 345 | 346 | next_latency += op_latency[opcode]; 347 | 348 | if (next_latency <= TOTAL_LATENCY) 349 | { 350 | if (is_rotation[opcode]) 351 | { 352 | ++rotate_count; 353 | } 354 | 355 | // Mark ALU as busy only for the first cycle when it starts executing the instruction because ALUs are fully pipelined 356 | alu_busy[next_latency - op_latency[opcode]][alu_index] = true; 357 | latency[a] = next_latency; 358 | 359 | // ASIC is supposed to have enough ALUs to run as many independent instructions per cycle as possible, so latency calculation for ASIC is simple 360 | asic_latency[a] = ((asic_latency[a] > asic_latency[b]) ? asic_latency[a] : asic_latency[b]) + asic_op_latency[opcode]; 361 | 362 | rotated[a] = is_rotation[opcode]; 363 | 364 | inst_data[a] = code_size + (opcode << 8) + ((inst_data[b] & 255) << 16); 365 | 366 | code[code_size].opcode = opcode; 367 | code[code_size].dst_index = dst_index; 368 | code[code_size].src_index = src_index; 369 | code[code_size].C = 0; 370 | 371 | if (src_index == 8) 372 | { 373 | r8_used = true; 374 | } 375 | 376 | if (opcode == ADD) 377 | { 378 | // ADD instruction is implemented as two 1-cycle instructions on a real CPU, so mark ALU as busy for the next cycle too 379 | alu_busy[next_latency - op_latency[opcode] + 1][alu_index] = true; 380 | 381 | // ADD instruction requires 4 more random bytes for 32-bit constant "C" in "a = a + b + C" 382 | check_data(&data_index, sizeof(uint32_t), data, sizeof(data)); 383 | uint32_t t; 384 | memcpy(&t, data + data_index, sizeof(uint32_t)); 385 | code[code_size].C = (t); 386 | data_index += sizeof(uint32_t); 387 | } 388 | 389 | ++code_size; 390 | if (code_size >= NUM_INSTRUCTIONS_MIN) 391 | { 392 | break; 393 | } 394 | } 395 | else 396 | { 397 | ++num_retries; 398 | } 399 | } 400 | 401 | // ASIC has more execution resources and can extract as much parallelism from the code as possible 402 | // We need to add a few more MUL and ROR instructions to achieve minimal required latency for ASIC 403 | // Get this latency for at least 1 of the 4 registers 404 | const int prev_code_size = code_size; 405 | while ((code_size < NUM_INSTRUCTIONS_MAX) && (asic_latency[0] < TOTAL_LATENCY) && (asic_latency[1] < TOTAL_LATENCY) && (asic_latency[2] < TOTAL_LATENCY) && (asic_latency[3] < TOTAL_LATENCY)) 406 | { 407 | int min_idx = 0; 408 | int max_idx = 0; 409 | for (int i = 1; i < 4; ++i) 410 | { 411 | if (asic_latency[i] < asic_latency[min_idx]) min_idx = i; 412 | if (asic_latency[i] > asic_latency[max_idx]) max_idx = i; 413 | } 414 | 415 | const uint8_t pattern[3] = { ROR, MUL, MUL }; 416 | const uint8_t opcode = pattern[(code_size - prev_code_size) % 3]; 417 | latency[min_idx] = latency[max_idx] + op_latency[opcode]; 418 | asic_latency[min_idx] = asic_latency[max_idx] + asic_op_latency[opcode]; 419 | 420 | code[code_size].opcode = opcode; 421 | code[code_size].dst_index = min_idx; 422 | code[code_size].src_index = max_idx; 423 | code[code_size].C = 0; 424 | ++code_size; 425 | } 426 | 427 | // There is ~98.15% chance that loop condition is false, so this loop will execute only 1 iteration most of the time 428 | // It never does more than 4 iterations for all block heights < 10,000,000 429 | } while (!r8_used || (code_size < NUM_INSTRUCTIONS_MIN) || (code_size > NUM_INSTRUCTIONS_MAX)); 430 | 431 | // It's guaranteed that NUM_INSTRUCTIONS_MIN <= code_size <= NUM_INSTRUCTIONS_MAX here 432 | // Add final instruction to stop the interpreter 433 | code[code_size].opcode = RET; 434 | code[code_size].dst_index = 0; 435 | code[code_size].src_index = 0; 436 | code[code_size].C = 0; 437 | 438 | return code_size; 439 | } 440 | 441 | #endif 442 | -------------------------------------------------------------------------------- /MoneroKitSample/iOS/Main.storyboard: -------------------------------------------------------------------------------- 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 | 26 | 27 | 28 | 29 | 30 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 90 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 117 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | --------------------------------------------------------------------------------