├── 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 | [](https://github.com/djphoenix/MoneroKit/releases) [](https://github.com/djphoenix/MoneroKit/issues) [](https://github.com/djphoenix/MoneroKit/pulls) [](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 |
--------------------------------------------------------------------------------