diff --git a/Adamant.xcodeproj/project.pbxproj b/Adamant.xcodeproj/project.pbxproj index a42f3c531..fd5688bdc 100644 --- a/Adamant.xcodeproj/project.pbxproj +++ b/Adamant.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 4411402421C8B290703B13EB /* Pods_Adamant.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C107D5CB65B4D728B9D97C0F /* Pods_Adamant.framework */; }; 642361BE20E3869D0061559E /* eth_l18n.strings in Resources */ = {isa = PBXBuildFile; fileRef = 642361BD20E3869D0061559E /* eth_l18n.strings */; }; + 643ED0B12109F4BD005A9FDA /* NativeAdamantCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 643ED0B02109F4BD005A9FDA /* NativeAdamantCore.swift */; }; 644EC34D20EFA60900F40C73 /* AdamantApi+Delegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EC34C20EFA60900F40C73 /* AdamantApi+Delegates.swift */; }; 644EC34F20EFA77A00F40C73 /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EC34E20EFA77A00F40C73 /* Delegate.swift */; }; 644EC35220EFA9A300F40C73 /* DelegateRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EC35120EFA9A300F40C73 /* DelegateRoutes.swift */; }; @@ -19,6 +20,8 @@ 644EC35E20F34F1E00F40C73 /* DelegateDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EC35D20F34F1E00F40C73 /* DelegateDetailsViewController.swift */; }; 6455E9F121075D3600B2E94C /* AddressBookService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6455E9F021075D3600B2E94C /* AddressBookService.swift */; }; 6455E9F321075D8000B2E94C /* AdamantAddressBookService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6455E9F221075D8000B2E94C /* AdamantAddressBookService.swift */; }; + 645E7B062111DF3A006CC9FD /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 645E7B052111DF3A006CC9FD /* Crypto.swift */; }; + 649E9A152111B3C200686B01 /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649E9A142111B3C200686B01 /* Mnemonic.swift */; }; 64A223D620F760BB005157CB /* Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A223D520F760BB005157CB /* Localization.swift */; }; 64A223D820F7A08E005157CB /* LskApiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A223D720F7A08E005157CB /* LskApiService.swift */; }; 64A223DA20F7A14B005157CB /* AdamantLskApiService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A223D920F7A14B005157CB /* AdamantLskApiService.swift */; }; @@ -46,7 +49,6 @@ E913C8F91FFFA51D001A83F7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E913C8F81FFFA51D001A83F7 /* Assets.xcassets */; }; E913C9081FFFA943001A83F7 /* AdamantCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E913C9071FFFA943001A83F7 /* AdamantCore.swift */; }; E913C90D1FFFA99B001A83F7 /* Keypair.swift in Sources */ = {isa = PBXBuildFile; fileRef = E913C90C1FFFA99B001A83F7 /* Keypair.swift */; }; - E913C9171FFFAF76001A83F7 /* JSAdamantCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E913C9161FFFAF76001A83F7 /* JSAdamantCore.swift */; }; E9147B5F20500E9300145913 /* MyLittlePinpad+adamant.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9147B5E20500E9300145913 /* MyLittlePinpad+adamant.swift */; }; E9147B612050599000145913 /* LoginViewController+QR.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9147B602050599000145913 /* LoginViewController+QR.swift */; }; E9147B6320505C7500145913 /* QRCodeReader+adamant.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9147B6220505C7500145913 /* QRCodeReader+adamant.swift */; }; @@ -77,6 +79,12 @@ E921597520611A6A0000CA5C /* AdamantReachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = E921597420611A6A0000CA5C /* AdamantReachability.swift */; }; E921597B206503000000CA5C /* ButtonsStripeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E921597A206503000000CA5C /* ButtonsStripeView.swift */; }; E921597D2065031D0000CA5C /* ButtonsStripe.xib in Resources */ = {isa = PBXBuildFile; fileRef = E921597C2065031D0000CA5C /* ButtonsStripe.xib */; }; + E9220E0D21988EEA009C9642 /* ChatModels.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = E95F85B1200954D00070534A /* ChatModels.xcdatamodeld */; }; + E9220E1121988F81009C9642 /* JSAdamantCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9220E0221983155009C9642 /* JSAdamantCore.swift */; }; + E9220E1221988F81009C9642 /* adamant-core.js in Resources */ = {isa = PBXBuildFile; fileRef = E9220E0121983155009C9642 /* adamant-core.js */; }; + E9220E1321988F81009C9642 /* JSAdamantCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85762007E8EC0070534A /* JSAdamantCoreTests.swift */; }; + E9220E1421988F81009C9642 /* NativeCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9220E07219879B9009C9642 /* NativeCoreTests.swift */; }; + E9220E1521988FCE009C9642 /* JSModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F856A200789450070534A /* JSModels.swift */; }; E923222621135F9000A7E5AF /* EthAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = E923222521135F9000A7E5AF /* EthAccount.swift */; }; E9240BF5215D686500187B09 /* AdmWalletService+RichMessageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9240BF4215D686500187B09 /* AdmWalletService+RichMessageProvider.swift */; }; E9240BF9215D813A00187B09 /* CustomCellDeleage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9240BF8215D813A00187B09 /* CustomCellDeleage.swift */; }; @@ -126,17 +134,14 @@ E95CB456205D77B500A7218E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E95CB458205D77B500A7218E /* Localizable.strings */; }; E95CB45E205D7F9600A7218E /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = E95CB460205D7F9600A7218E /* Localizable.stringsdict */; }; E95F85692006AB9D0070534A /* NormalizedTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85682006AB9D0070534A /* NormalizedTransaction.swift */; }; - E95F856B200789450070534A /* JSModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F856A200789450070534A /* JSModels.swift */; }; E95F856F2007B61D0070534A /* GetPublicKeyResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F856E2007B61D0070534A /* GetPublicKeyResponse.swift */; }; E95F85712007D98D0070534A /* CurrencyFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85702007D98D0070534A /* CurrencyFormatterTests.swift */; }; E95F85752007E4790070534A /* HexAndBytesUtilitiesTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85742007E4790070534A /* HexAndBytesUtilitiesTest.swift */; }; - E95F85772007E8EC0070534A /* JSAdamantCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85762007E8EC0070534A /* JSAdamantCoreTests.swift */; }; E95F857A2007F0260070534A /* ServerResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85792007F0260070534A /* ServerResponse.swift */; }; E95F85802008C8D70070534A /* ChatsRoutes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F857E2008C8D60070534A /* ChatsRoutes.swift */; }; E95F85852008CB3A0070534A /* ChatListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85842008CB3A0070534A /* ChatListViewController.swift */; }; E95F85872008FDBF0070534A /* ChatAsset.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85862008FDBF0070534A /* ChatAsset.swift */; }; E95F8589200900B10070534A /* ChatType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F8588200900B10070534A /* ChatType.swift */; }; - E95F85B3200954D00070534A /* ChatModels.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = E95F85B1200954D00070534A /* ChatModels.xcdatamodeld */; }; E95F85B7200A4D8F0070534A /* TestTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85B6200A4D8F0070534A /* TestTools.swift */; }; E95F85BA200A4DC90070534A /* TransactionSend.json in Resources */ = {isa = PBXBuildFile; fileRef = E95F85B9200A4DC90070534A /* TransactionSend.json */; }; E95F85BC200A4E670070534A /* ParsingModelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95F85BB200A4E670070534A /* ParsingModelsTests.swift */; }; @@ -203,7 +208,6 @@ E9B4E1A8210F079E007E77FC /* DoubleDetailsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9B4E1A7210F079E007E77FC /* DoubleDetailsTableViewCell.swift */; }; E9B4E1AA210F1803007E77FC /* DoubleDetailsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E9B4E1A9210F08BE007E77FC /* DoubleDetailsTableViewCell.xib */; }; E9C51ECF200E2D1100385EB7 /* FeeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9C51ECE200E2D1100385EB7 /* FeeTests.swift */; }; - E9C51EED2011416E00385EB7 /* adamant-core.js in Resources */ = {isa = PBXBuildFile; fileRef = E9C51EEC2011416E00385EB7 /* adamant-core.js */; }; E9C51EEF20139DC600385EB7 /* TransactionIdResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9C51EEE20139DC600385EB7 /* TransactionIdResponse.swift */; }; E9C51EF12013F18000385EB7 /* NewChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9C51EF02013F18000385EB7 /* NewChatViewController.swift */; }; E9CAE8D22018AA7700345E76 /* AdamantApi+Accounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9CAE8D12018AA7700345E76 /* AdamantApi+Accounts.swift */; }; @@ -214,7 +218,6 @@ E9D1BE1A211DA25300E86B72 /* UIView+constraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D1BE19211DA25300E86B72 /* UIView+constraints.swift */; }; E9D1BE1C211DABE100E86B72 /* WalletPagingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9D1BE1B211DABE100E86B72 /* WalletPagingItem.swift */; }; E9DFB71C21624C9200CF8C7C /* AdmTransactionDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFB71B21624C9200CF8C7C /* AdmTransactionDetailsViewController.swift */; }; - E9DFB71E21651FBE00CF8C7C /* JSAdamantCore+Native.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFB71D21651FBD00CF8C7C /* JSAdamantCore+Native.swift */; }; E9DFB720216619F400CF8C7C /* BaseTransaction+TransactionDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DFB71F216619F400CF8C7C /* BaseTransaction+TransactionDetails.swift */; }; E9E7CD8B20026B0600DFC4DB /* AccountService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E7CD8A20026B0600DFC4DB /* AccountService.swift */; }; E9E7CD8D20026B6600DFC4DB /* DialogService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E7CD8C20026B6600DFC4DB /* DialogService.swift */; }; @@ -268,6 +271,7 @@ /* Begin PBXFileReference section */ 642361BD20E3869D0061559E /* eth_l18n.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = eth_l18n.strings; sourceTree = ""; }; + 643ED0B02109F4BD005A9FDA /* NativeAdamantCore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeAdamantCore.swift; sourceTree = ""; }; 644EC34C20EFA60900F40C73 /* AdamantApi+Delegates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdamantApi+Delegates.swift"; sourceTree = ""; }; 644EC34E20EFA77A00F40C73 /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = ""; }; 644EC35120EFA9A300F40C73 /* DelegateRoutes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateRoutes.swift; sourceTree = ""; }; @@ -278,6 +282,8 @@ 644EC35D20F34F1E00F40C73 /* DelegateDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateDetailsViewController.swift; sourceTree = ""; }; 6455E9F021075D3600B2E94C /* AddressBookService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressBookService.swift; sourceTree = ""; }; 6455E9F221075D8000B2E94C /* AdamantAddressBookService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdamantAddressBookService.swift; sourceTree = ""; }; + 645E7B052111DF3A006CC9FD /* Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = ""; }; + 649E9A142111B3C200686B01 /* Mnemonic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = ""; }; 64A223D520F760BB005157CB /* Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localization.swift; sourceTree = ""; }; 64A223D720F7A08E005157CB /* LskApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LskApiService.swift; sourceTree = ""; }; 64A223D920F7A14B005157CB /* AdamantLskApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdamantLskApiService.swift; sourceTree = ""; }; @@ -316,7 +322,6 @@ E913C8FD1FFFA51E001A83F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; E913C9071FFFA943001A83F7 /* AdamantCore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdamantCore.swift; sourceTree = ""; }; E913C90C1FFFA99B001A83F7 /* Keypair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keypair.swift; sourceTree = ""; }; - E913C9161FFFAF76001A83F7 /* JSAdamantCore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAdamantCore.swift; sourceTree = ""; }; E9147B5E20500E9300145913 /* MyLittlePinpad+adamant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MyLittlePinpad+adamant.swift"; sourceTree = ""; }; E9147B602050599000145913 /* LoginViewController+QR.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoginViewController+QR.swift"; sourceTree = ""; }; E9147B6220505C7500145913 /* QRCodeReader+adamant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QRCodeReader+adamant.swift"; sourceTree = ""; }; @@ -359,6 +364,9 @@ E921597420611A6A0000CA5C /* AdamantReachability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdamantReachability.swift; sourceTree = ""; }; E921597A206503000000CA5C /* ButtonsStripeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonsStripeView.swift; sourceTree = ""; }; E921597C2065031D0000CA5C /* ButtonsStripe.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ButtonsStripe.xib; sourceTree = ""; }; + E9220E0121983155009C9642 /* adamant-core.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "adamant-core.js"; sourceTree = ""; }; + E9220E0221983155009C9642 /* JSAdamantCore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAdamantCore.swift; sourceTree = ""; }; + E9220E07219879B9009C9642 /* NativeCoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeCoreTests.swift; sourceTree = ""; }; E923222521135F9000A7E5AF /* EthAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthAccount.swift; sourceTree = ""; }; E9240BF4215D686500187B09 /* AdmWalletService+RichMessageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdmWalletService+RichMessageProvider.swift"; sourceTree = ""; }; E9240BF8215D813A00187B09 /* CustomCellDeleage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCellDeleage.swift; sourceTree = ""; }; @@ -487,7 +495,6 @@ E9B4E1A7210F079E007E77FC /* DoubleDetailsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleDetailsTableViewCell.swift; sourceTree = ""; }; E9B4E1A9210F08BE007E77FC /* DoubleDetailsTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DoubleDetailsTableViewCell.xib; sourceTree = ""; }; E9C51ECE200E2D1100385EB7 /* FeeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeeTests.swift; sourceTree = ""; }; - E9C51EEC2011416E00385EB7 /* adamant-core.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "adamant-core.js"; sourceTree = ""; }; E9C51EEE20139DC600385EB7 /* TransactionIdResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionIdResponse.swift; sourceTree = ""; }; E9C51EF02013F18000385EB7 /* NewChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewChatViewController.swift; sourceTree = ""; }; E9CAE8D12018AA7700345E76 /* AdamantApi+Accounts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdamantApi+Accounts.swift"; sourceTree = ""; }; @@ -598,6 +605,7 @@ 54F4E3CDA748B7F48C085503 /* Frameworks */, E59396A8E0053F21F768E69B /* Pods */, E913C8EF1FFFA51D001A83F7 /* Products */, + E9220E0C21988D9A009C9642 /* Recovered References */, ); sourceTree = ""; }; @@ -669,8 +677,7 @@ E9A03FD720DC0ABA007653A1 /* AdamantNodesSource.swift */, E93D7ABF2052CF63005D19DC /* AdamantNotificationService.swift */, E921597420611A6A0000CA5C /* AdamantReachability.swift */, - E913C9161FFFAF76001A83F7 /* JSAdamantCore.swift */, - E9DFB71D21651FBD00CF8C7C /* JSAdamantCore+Native.swift */, + 643ED0B02109F4BD005A9FDA /* NativeAdamantCore.swift */, E905D39A2048A9BD00DDB504 /* KeychainStore.swift */, E950273F202E257E002C1098 /* RepeaterService.swift */, E9E7CDB42002BA6900DFC4DB /* SwinjectedRouter.swift */, @@ -718,7 +725,6 @@ E9204B4F20C94C4A00F3B9AB /* Date+humanizedString.swift */, E9393FA72055C92700EE6F30 /* Decimal+adamant.swift */, E98FC34720F921EA00032D65 /* DelegateVote.swift */, - E95F856A200789450070534A /* JSModels.swift */, E913C90C1FFFA99B001A83F7 /* Keypair.swift */, 64A223D520F760BB005157CB /* Localization.swift */, E9147B5E20500E9300145913 /* MyLittlePinpad+adamant.swift */, @@ -741,7 +747,6 @@ E913C8F81FFFA51D001A83F7 /* Assets.xcassets */, E9A174B820587B83003667CD /* notification.mp3 */, E9256F752039A9A200DE86E9 /* LaunchScreen.storyboard */, - E9C51EEC2011416E00385EB7 /* adamant-core.js */, 642361BD20E3869D0061559E /* eth_l18n.strings */, ); path = Assets; @@ -784,6 +789,26 @@ path = ServerResponses; sourceTree = ""; }; + E9220E0021983145009C9642 /* Core */ = { + isa = PBXGroup; + children = ( + E95F856A200789450070534A /* JSModels.swift */, + E9220E0221983155009C9642 /* JSAdamantCore.swift */, + E9220E0121983155009C9642 /* adamant-core.js */, + E95F85762007E8EC0070534A /* JSAdamantCoreTests.swift */, + E9220E07219879B9009C9642 /* NativeCoreTests.swift */, + ); + path = Core; + sourceTree = ""; + }; + E9220E0C21988D9A009C9642 /* Recovered References */ = { + isa = PBXGroup; + children = ( + E9DFB71D21651FBD00CF8C7C /* JSAdamantCore+Native.swift */, + ); + name = "Recovered References"; + sourceTree = ""; + }; E93EB09D20DA3F3A001F9601 /* NodesEditor */ = { isa = PBXGroup; children = ( @@ -871,6 +896,8 @@ E9942B83203CBFCE00C163AF /* AdamantQRTools.swift */, E9E7CDB62003994E00DFC4DB /* AdamantUtilities.swift */, E950652220404C84008352E5 /* AdamantUriTools.swift */, + 649E9A142111B3C200686B01 /* Mnemonic.swift */, + 645E7B052111DF3A006CC9FD /* Crypto.swift */, ); path = Utilities; sourceTree = ""; @@ -1050,6 +1077,7 @@ E9EC344520066D4A00C0E546 /* AdamantTests */ = { isa = PBXGroup; children = ( + E9220E0021983145009C9642 /* Core */, E95F85B8200A4D9C0070534A /* Parsing */, E950652020404BF0008352E5 /* AdamantUriBuilding.swift */, E9EC344620066D4A00C0E546 /* AddressValidationTests.swift */, @@ -1057,7 +1085,6 @@ E95F85702007D98D0070534A /* CurrencyFormatterTests.swift */, E9C51ECE200E2D1100385EB7 /* FeeTests.swift */, E95F85742007E4790070534A /* HexAndBytesUtilitiesTest.swift */, - E95F85762007E8EC0070534A /* JSAdamantCoreTests.swift */, E95F85B6200A4D8F0070534A /* TestTools.swift */, E9EC344820066D4A00C0E546 /* Info.plist */, ); @@ -1186,7 +1213,6 @@ E9942B89203D9ECA00C163AF /* QrCell.xib in Resources */, E9FEECAA2143C371007DD7C8 /* TransferCollectionViewCell.xib in Resources */, E921597D2065031D0000CA5C /* ButtonsStripe.xib in Resources */, - E9C51EED2011416E00385EB7 /* adamant-core.js in Resources */, E90A4945204C6204009F6A65 /* PassphraseCell.xib in Resources */, E941CCDF20E7B70200C96220 /* WalletCollectionViewCell.xib in Resources */, 642361BE20E3869D0061559E /* eth_l18n.strings in Resources */, @@ -1225,6 +1251,7 @@ E95F85C2200A53E90070534A /* NormalizedTransaction.json in Resources */, E95F85BE200A503A0070534A /* TransactionChat.json in Resources */, E95F85C4200A540B0070534A /* Chat.json in Resources */, + E9220E1221988F81009C9642 /* adamant-core.js in Resources */, E95F85BA200A4DC90070534A /* TransactionSend.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1241,6 +1268,7 @@ "${PODS_ROOT}/Target Support Files/Pods-Adamant/Pods-Adamant-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/BigInt/BigInt.framework", + "${BUILT_PRODUCTS_DIR}/ByteBackpacker/ByteBackpacker.framework", "${BUILT_PRODUCTS_DIR}/CryptoSwift/CryptoSwift.framework", "${BUILT_PRODUCTS_DIR}/DateToolsSwift/DateToolsSwift.framework", "${BUILT_PRODUCTS_DIR}/EFQRCode/EFQRCode.framework", @@ -1274,6 +1302,7 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BigInt.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ByteBackpacker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CryptoSwift.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DateToolsSwift.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/EFQRCode.framework", @@ -1415,7 +1444,6 @@ 644EC35220EFA9A300F40C73 /* DelegateRoutes.swift in Sources */, E926E032213EC43B005E536B /* FullscreenAlertView.swift in Sources */, 644EC35B20EFB8E900F40C73 /* AdamantDelegateCell.swift in Sources */, - E95F85B3200954D00070534A /* ChatModels.xcdatamodeld in Sources */, E90A494B204D9EB8009F6A65 /* AdamantAuthentication.swift in Sources */, E9215973206119FB0000CA5C /* ReachabilityMonitor.swift in Sources */, E91947B420002809001362F8 /* AdamantAccount.swift in Sources */, @@ -1441,6 +1469,7 @@ E941CCDE20E7B70200C96220 /* WalletCollectionViewCell.swift in Sources */, E9150B9E2066DA210065A985 /* Chatroom+CoreDataProperties.swift in Sources */, E9AA8BFA212C166600F9249F /* EthWalletService+Send.swift in Sources */, + E9220E0D21988EEA009C9642 /* ChatModels.xcdatamodeld in Sources */, E91947B22000246A001362F8 /* AdamantError.swift in Sources */, E95F85802008C8D70070534A /* ChatsRoutes.swift in Sources */, E9942B87203D9E5100C163AF /* EurekaQRRow.swift in Sources */, @@ -1450,7 +1479,9 @@ E927171E20C04614002BB9A6 /* UIColor+hex.swift in Sources */, E99818942120892F0018C84C /* WalletViewControllerBase.swift in Sources */, E9B3D39E201F99F40019EB36 /* DataProvider.swift in Sources */, + 643ED0B12109F4BD005A9FDA /* NativeAdamantCore.swift in Sources */, E93EB0A320DA4CCA001F9601 /* Node.swift in Sources */, + 645E7B062111DF3A006CC9FD /* Crypto.swift in Sources */, E9E7CDC02003AF6D00DFC4DB /* AdamantCellFactory.swift in Sources */, E9D1BE1A211DA25300E86B72 /* UIView+constraints.swift in Sources */, E9DFB71C21624C9200CF8C7C /* AdmTransactionDetailsViewController.swift in Sources */, @@ -1465,6 +1496,7 @@ E9DFB720216619F400CF8C7C /* BaseTransaction+TransactionDetails.swift in Sources */, E9E7CDCA20040CC200DFC4DB /* Transaction.swift in Sources */, E9AA8BFC212C169200F9249F /* EthWalletService+Transfers.swift in Sources */, + 649E9A152111B3C200686B01 /* Mnemonic.swift in Sources */, E95F85692006AB9D0070534A /* NormalizedTransaction.swift in Sources */, E9150B9B2066DA210065A985 /* BaseTransaction+CoreDataClass.swift in Sources */, E9150B9A2066DA210065A985 /* TransferTransaction+CoreDataProperties.swift in Sources */, @@ -1517,11 +1549,9 @@ 644EC35720EFAAB700F40C73 /* DelegatesListViewController.swift in Sources */, E9C51EF12013F18000385EB7 /* NewChatViewController.swift in Sources */, E9B4E1A8210F079E007E77FC /* DoubleDetailsTableViewCell.swift in Sources */, - E913C9171FFFAF76001A83F7 /* JSAdamantCore.swift in Sources */, E9FEECA92143C371007DD7C8 /* TransferCollectionViewCell.swift in Sources */, E9502740202E257E002C1098 /* RepeaterService.swift in Sources */, E93D7AC02052CF63005D19DC /* AdamantNotificationService.swift in Sources */, - E9DFB71E21651FBE00CF8C7C /* JSAdamantCore+Native.swift in Sources */, E93B0D762028B28E00126346 /* AdamantChatsProvider.swift in Sources */, E993302021354B1800CD5200 /* AdmWalletRoutes.swift in Sources */, 64FA53D120E24942006783C9 /* TransactionDetailsViewControllerBase.swift in Sources */, @@ -1543,7 +1573,6 @@ E98FC34220F9209900032D65 /* UIColor+adamant.swift in Sources */, E948E04C2027679300975D6B /* AdamantFormattingTools.swift in Sources */, E9E7CDB12002B97B00DFC4DB /* AccountRoutes.swift in Sources */, - E95F856B200789450070534A /* JSModels.swift in Sources */, E9240BF9215D813A00187B09 /* CustomCellDeleage.swift in Sources */, E9AA8BF82129F13000F9249F /* ComplexTransferViewController.swift in Sources */, E9A174B52057EDCE003667CD /* AdamantTransfersProvider+backgroundFetch.swift in Sources */, @@ -1562,13 +1591,16 @@ files = ( E9C51ECF200E2D1100385EB7 /* FeeTests.swift in Sources */, E9EC344720066D4A00C0E546 /* AddressValidationTests.swift in Sources */, + E9220E1321988F81009C9642 /* JSAdamantCoreTests.swift in Sources */, E94883E7203F07CD00F6E1B0 /* PassphraseValidation.swift in Sources */, E95F85B7200A4D8F0070534A /* TestTools.swift in Sources */, E95F85BC200A4E670070534A /* ParsingModelsTests.swift in Sources */, + E9220E1521988FCE009C9642 /* JSModels.swift in Sources */, E95F85752007E4790070534A /* HexAndBytesUtilitiesTest.swift in Sources */, - E95F85772007E8EC0070534A /* JSAdamantCoreTests.swift in Sources */, + E9220E1121988F81009C9642 /* JSAdamantCore.swift in Sources */, E95F85712007D98D0070534A /* CurrencyFormatterTests.swift in Sources */, E950652120404BF0008352E5 /* AdamantUriBuilding.swift in Sources */, + E9220E1421988F81009C9642 /* NativeCoreTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Adamant.xcodeproj/xcshareddata/xcbaselines/E9EC344320066D4A00C0E546.xcbaseline/2F5A2BDA-A1C8-4C51-B0EB-6802181570B4.plist b/Adamant.xcodeproj/xcshareddata/xcbaselines/E9EC344320066D4A00C0E546.xcbaseline/2F5A2BDA-A1C8-4C51-B0EB-6802181570B4.plist index 80c9b65b8..f828ec7b7 100644 --- a/Adamant.xcodeproj/xcshareddata/xcbaselines/E9EC344320066D4A00C0E546.xcbaseline/2F5A2BDA-A1C8-4C51-B0EB-6802181570B4.plist +++ b/Adamant.xcodeproj/xcshareddata/xcbaselines/E9EC344320066D4A00C0E546.xcbaseline/2F5A2BDA-A1C8-4C51-B0EB-6802181570B4.plist @@ -37,6 +37,39 @@ + NativeCoreTests + + testPerformanceHashForPassphrase() + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 1.179 + baselineIntegrationDisplayName + Local Baseline + + + testPerformanceKeypairForPassphrase() + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 1.1729 + baselineIntegrationDisplayName + Local Baseline + + + testPerformanceSignTransaction() + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0.0018654 + baselineIntegrationDisplayName + Local Baseline + + + diff --git a/Adamant.xcodeproj/xcshareddata/xcschemes/Adamant.Dev.BackgroundFetch.xcscheme b/Adamant.xcodeproj/xcshareddata/xcschemes/Adamant.Dev.BackgroundFetch.xcscheme index b89be5051..1f9e9c6e2 100644 --- a/Adamant.xcodeproj/xcshareddata/xcschemes/Adamant.Dev.BackgroundFetch.xcscheme +++ b/Adamant.xcodeproj/xcshareddata/xcschemes/Adamant.Dev.BackgroundFetch.xcscheme @@ -1,6 +1,6 @@ Decimal { - return self * 100000000 + return Decimal(sign: self.isSignMinus ? .minus : .plus, exponent: -AdamantUtilities.currencyExponent, significand: self) } var doubleValue: Double { diff --git a/Adamant/Services/JSAdamantCore+Native.swift b/Adamant/Services/JSAdamantCore+Native.swift deleted file mode 100644 index a637d0db8..000000000 --- a/Adamant/Services/JSAdamantCore+Native.swift +++ /dev/null @@ -1,241 +0,0 @@ -// -// JSAdamantCore+Native.swift -// Adamant -// -// Created by Anton Boyarkin on 26/07/2018. -// Copyright © 2018 Adamant. All rights reserved. -// - -import Foundation -import libsodium - -extension JSAdamantCore { - func encodeValue(_ value: [String: Any], privateKey privateKeyHex: String) -> (message: String, nonce: String)? { - let data = ["payload": value] - - let padded: String = String.random(length: Int(arc4random_uniform(10)), alphabet: "abcdefghijklmnopqrstuvwxyz") + JSONStringify(value: data as AnyObject) + String.random(length: Int(arc4random_uniform(10)), alphabet: "abcdefghijklmnopqrstuvwxyz") - - let message = padded.bytes - let privateKey = privateKeyHex.hexBytes() - - guard let hash = hashSHA256(privateKey: privateKey) else { - print("FAIL to create SHA256 of private key") - return nil - } - - guard let secretKey = ed2curve(privateKey: hash) else { - print("FAIL to create ed2curve secret key from SHA256") - return nil - } - - guard let encrypted = seal(message: message, secretKey: secretKey) else { - print("FAIL to encrypt") - return nil - } - - let encryptedMessage = encrypted.authenticatedCipherText.hexString() - let nonce = encrypted.nonce.hexString() - - return (message: encryptedMessage, nonce: nonce) - } - - func decodeValue(rawMessage: String, rawNonce: String, privateKey privateKeyHex: String) -> String? { - let message = rawMessage.hexBytes() - let nonce = rawNonce.hexBytes() - let privateKey = privateKeyHex.hexBytes() - - guard let hash = hashSHA256(privateKey: privateKey) else { - print("FAIL to create SHA256 of private key") - return nil - } - - guard let secretKey = ed2curve(privateKey: hash) else { - print("FAIL to create ed2curve secret key from SHA256") - return nil - } - - guard let decrepted = open(authenticatedCipherText: message, secretKey: secretKey, nonce: nonce) else { - print("FAIL to decrypt") - return nil - } - - return decrepted.utf8String - } - - private func seal(message: Bytes, secretKey: Bytes) -> (authenticatedCipherText: Bytes, nonce: Bytes)? { - guard secretKey.count == KeyBytes else { return nil } - var authenticatedCipherText = Bytes(count: message.count + MacBytes) - let nonce = self.nonce() - - guard .SUCCESS == crypto_secretbox_easy ( - &authenticatedCipherText, - message, UInt64(message.count), - nonce, - secretKey - ).exitCode else { return nil } - - return (authenticatedCipherText: authenticatedCipherText, nonce: nonce) - } - - private func open(authenticatedCipherText: Bytes, secretKey: Bytes, nonce: Bytes) -> Bytes? { - guard authenticatedCipherText.count >= MacBytes else { return nil } - var message = Bytes(count: authenticatedCipherText.count - MacBytes) - - guard .SUCCESS == crypto_secretbox_open_easy ( - &message, - authenticatedCipherText, UInt64(authenticatedCipherText.count), - nonce, - secretKey - ).exitCode else { return nil } - - return message - } - - private func hashSHA256(privateKey: Bytes) -> Bytes? { - var hash = Bytes(count: HashSHA256Bytes) - - guard .SUCCESS == crypto_hash_sha256( - &hash, - privateKey, UInt64(privateKey.count) - ).exitCode else { return nil } - - return hash - } - - private func ed2curve(privateKey: Bytes) -> Bytes? { - var secretKey = Bytes(count: SecretKeyBytes) - - guard .SUCCESS == crypto_sign_ed25519_sk_to_curve25519( - &secretKey, - privateKey - ).exitCode else { return nil } - - return secretKey - } - - private func nonce() -> Bytes { - var nonce = Bytes(count: NonceBytes) - randombytes_buf(&nonce, NonceBytes) - return nonce - } -} - -// MARK:- Helpers -public let HashSHA256Bytes = Int(crypto_hash_sha256_bytes()) -public let SecretKeyBytes = Int(crypto_scalarmult_curve25519_bytes()) -public let MacBytes = Int(crypto_secretbox_macbytes()) -public let NonceBytes = Int(crypto_secretbox_noncebytes()) -public var KeyBytes = Int(crypto_secretbox_keybytes()) - -public typealias Bytes = Array - -extension Data { - func toString() -> String? { - return String(data: self, encoding: .utf8) - } -} - -extension Array where Element == UInt8 { - init (count bytes: Int) { - self.init(repeating: 0, count: bytes) - } - - public var utf8String: String? { - return String(data: Data(bytes: self), encoding: .utf8) - } - - func toData() -> Data { - return Data(bytes: self) - } -} - -extension ArraySlice where Element == UInt8 { - var bytes: Bytes { return Bytes(self) } -} - -extension String { - var bytes: Bytes { return Bytes(self.utf8) } - - func hexBytes() -> [UInt8] { - return (0.. [String: Any]? { - if let data = self.data(using: .utf8) { - do { - return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] - } catch { - print(error.localizedDescription) - } - } - return nil - } - - func matches(for regex: String) -> [String] { - do { - let regex = try NSRegularExpression(pattern: regex) - let results = regex.matches(in: self, - range: NSRange(self.startIndex..., in: self)) - return results.map { - String(self[Range($0.range, in: self)!]) - } - } catch let error { - print("invalid regex: \(error.localizedDescription)") - return [] - } - } - - subscript (i: Int) -> Character - { - return self[index(startIndex, offsetBy:i)] - } - - static func random(length: Int = 32, alphabet: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String - { - let upperBound = UInt32(alphabet.count) - return String((0.. Character in - return alphabet[Int(arc4random_uniform(upperBound))] - }) - } -} - -enum ExitCode { - case SUCCESS - case FAILURE - - init (from int: Int32) { - switch int { - case 0: self = .SUCCESS - default: self = .FAILURE - } - } -} - -extension Int32 { - var exitCode: ExitCode { return ExitCode(from: self) } -} - -extension Sequence where Self.Element == UInt8 { - internal func hexString() -> String { - return map { String(format: "%02hhx", $0) }.joined() - } -} - -func JSONStringify(value: AnyObject, prettyPrinted: Bool = false) -> String { - let options = prettyPrinted ? JSONSerialization.WritingOptions.prettyPrinted : [] - - if JSONSerialization.isValidJSONObject(value) { - if let data = try? JSONSerialization.data(withJSONObject: value, options: options) { - if let string = String(data: data, encoding: .utf8) { - return string - } - } - } - - return "" -} diff --git a/Adamant/Services/NativeAdamantCore.swift b/Adamant/Services/NativeAdamantCore.swift new file mode 100644 index 000000000..168ea6535 --- /dev/null +++ b/Adamant/Services/NativeAdamantCore.swift @@ -0,0 +1,257 @@ +// +// NativeAdamantCore.swift +// Adamant +// +// Created by Anton Boyarkin on 26/07/2018. +// Copyright © 2018 Adamant. All rights reserved. +// + +import Foundation +import CryptoSwift +import ByteBackpacker + +class NativeAdamantCore : AdamantCore { + + func createHashFor(passphrase: String) -> String? { + guard let hash = createRawHashFor(passphrase: passphrase) else { + print("Unable create hash from passphrase") + return nil + } + + return hash.hexString() + } + + func createKeypairFor(passphrase: String) -> Keypair? { + guard let hash = createRawHashFor(passphrase: passphrase) else { + print("Unable create hash from passphrase") + return nil + } + + guard let keypair = Crypto.sign.keypair(from: hash) else { + print("Unable create Keypair from seed") + return nil + } + + return Keypair(publicKey: keypair.publicKey.hexString(), privateKey: keypair.privateKey.hexString()) + } + + func generateNewPassphrase() -> String { + if let passphrase = try? Mnemonic.generate().joined(separator: " ") { + return passphrase + } + return "" + } + + func sign(transaction: SignableTransaction, senderId: String, keypair: Keypair) -> String? { + let privateKey = keypair.privateKey.hexBytes() + let hash = transaction.bytes.sha256() + + guard let signature = Crypto.sign.signature(message: hash, secretKey: privateKey) else { + print("FAIL to sign of transaction") + return nil + } + + return signature.hexString() + } + + func encodeMessage(_ message: String, recipientPublicKey publicKey: String, privateKey privateKeyHex: String) -> (message: String, nonce: String)? { + let message = message.bytes + let recipientKey = publicKey.hexBytes() + let privateKey = privateKeyHex.hexBytes() + + guard let publicKey = Crypto.ed2Curve.publicKey(recipientKey) else { + print("FAIL to create ed2curve publick key from SHA256") + return nil + } + + guard let secretKey = Crypto.ed2Curve.privateKey(privateKey) else { + print("FAIL to create ed2curve secret key from SHA256") + return nil + } + + guard let encrypted = Crypto.box.seal(message: message, recipientPublicKey: publicKey, senderSecretKey: secretKey) else { + print("FAIL to encrypt") + return nil + } + + let encryptedMessage = encrypted.authenticatedCipherText.hexString() + let nonce = encrypted.nonce.hexString() + + return (message: encryptedMessage, nonce: nonce) + } + + func decodeMessage(rawMessage: String, rawNonce: String, senderPublicKey senderKeyHex: String, privateKey privateKeyHex: String) -> String? { + let message = rawMessage.hexBytes() + let nonce = rawNonce.hexBytes() + let senderKey = senderKeyHex.hexBytes() + let privateKey = privateKeyHex.hexBytes() + + guard let publicKey = Crypto.ed2Curve.publicKey(senderKey) else { + print("FAIL to create ed2curve publick key from SHA256") + return nil + } + + guard let secretKey = Crypto.ed2Curve.privateKey(privateKey) else { + print("FAIL to create ed2curve secret key from SHA256") + return nil + } + + guard let decrepted = Crypto.box.open(authenticatedCipherText: message, senderPublicKey: publicKey, recipientSecretKey: secretKey, nonce: nonce) else { + print("FAIL to decrypt") + return nil + } + + return decrepted.utf8String + } + + func encodeValue(_ value: [String: Any], privateKey privateKeyHex: String) -> (message: String, nonce: String)? { + let data = ["payload": value] + + let padded: String = String.random(length: Int(arc4random_uniform(10)), alphabet: "abcdefghijklmnopqrstuvwxyz") + JSONStringify(value: data as AnyObject) + String.random(length: Int(arc4random_uniform(10)), alphabet: "abcdefghijklmnopqrstuvwxyz") + + let message = padded.bytes + let privateKey = privateKeyHex.hexBytes() + let hash = privateKey.sha256() + + guard let secretKey = Crypto.ed2Curve.privateKey(hash) else { + print("FAIL to create ed2curve secret key from SHA256") + return nil + } + + guard let encrypted = Crypto.secretBox.seal(message: message, secretKey: secretKey) else { + print("FAIL to encrypt") + return nil + } + + let encryptedMessage = encrypted.authenticatedCipherText.hexString() + let nonce = encrypted.nonce.hexString() + + return (message: encryptedMessage, nonce: nonce) + } + + func decodeValue(rawMessage: String, rawNonce: String, privateKey privateKeyHex: String) -> String? { + let message = rawMessage.hexBytes() + let nonce = rawNonce.hexBytes() + let privateKey = privateKeyHex.hexBytes() + let hash = privateKey.sha256() + + guard let secretKey = Crypto.ed2Curve.privateKey(hash) else { + print("FAIL to create ed2curve secret key from SHA256") + return nil + } + + guard let decrepted = Crypto.secretBox.open(authenticatedCipherText: message, secretKey: secretKey, nonce: nonce) else { + print("FAIL to decrypt") + return nil + } + + return decrepted.utf8String + } + + // MARK: - Private tools + private func createRawHashFor(passphrase: String) -> [UInt8]? { + guard let seed = Mnemonic.seed(passphrase: passphrase) else { + print("FAIL to create Seed from passphrase bytes") + return nil + } + + return seed.sha256() + } +} + +func JSONStringify(value: AnyObject, prettyPrinted: Bool = false) -> String { + let options = prettyPrinted ? JSONSerialization.WritingOptions.prettyPrinted : [] + + if JSONSerialization.isValidJSONObject(value) { + if let data = try? JSONSerialization.data(withJSONObject: value, options: options) { + if let string = String(data: data, encoding: .utf8) { + return string + } + } + } + + return "" +} + +// MARK: - Bytes +extension SignableTransaction { + + var bytes: [UInt8] { + return + typeBytes + + timestampBytes + + senderPublicKeyBytes + + requesterPublicKeyBytes + + recipientIdBytes + + amountBytes + + assetBytes + + signatureBytes + + signSignatureBytes + } + + var typeBytes: [UInt8] { + return [UInt8(type.rawValue)] + } + + var timestampBytes: [UInt8] { + return ByteBackpacker.pack(UInt32(timestamp), byteOrder: .littleEndian) + } + + var senderPublicKeyBytes: [UInt8] { + return senderPublicKey.hexBytes() + } + + var requesterPublicKeyBytes: [UInt8] { + return requesterPublicKey?.hexBytes() ?? [] + } + + var recipientIdBytes: [UInt8] { + guard + let value = recipientId?.replacingOccurrences(of: "U", with: ""), + let number = UInt64(value) else { return Bytes(count: 8) } + return ByteBackpacker.pack(number, byteOrder: .bigEndian) + } + + var amountBytes: [UInt8] { + let value = (self.amount.shiftedToAdamant() as NSDecimalNumber).uint64Value + let bytes = ByteBackpacker.pack(value, byteOrder: .littleEndian) + return bytes + } + + var signatureBytes: [UInt8] { + return [] + } + + var signSignatureBytes: [UInt8] { + return [] + } + + var assetBytes: [UInt8] { + switch type { + case .chatMessage: + guard let msg = asset.chat?.message, let own = asset.chat?.ownMessage, let type = asset.chat?.type else { return [] } + + return msg.hexBytes() + own.hexBytes() + ByteBackpacker.pack(UInt32(type.rawValue), byteOrder: .littleEndian) + + case .state: + guard let key = asset.state?.key, let value = asset.state?.value, let type = asset.state?.type else { return [] } + + return value.bytes + key.bytes + ByteBackpacker.pack(UInt32(type.rawValue), byteOrder: .littleEndian) + + case .vote: + guard + let votes = asset.votes?.votes + else { return [] } + + var bytes = [UInt8]() + for vote in votes { + bytes += vote.bytes + } + + return bytes + + default: + return [] + } + } +} diff --git a/Adamant/Services/TokensApiService/AdamantLskApiService.swift b/Adamant/Services/TokensApiService/AdamantLskApiService.swift index cef45f409..eee59458e 100644 --- a/Adamant/Services/TokensApiService/AdamantLskApiService.swift +++ b/Adamant/Services/TokensApiService/AdamantLskApiService.swift @@ -38,9 +38,10 @@ class AdamantLskApiService: LskApiService { } func newAccount(byPassphrase passphrase: String, completion: @escaping (ApiServiceResult) -> Void) { + /* do { - let keys = try Crypto.keyPair(fromPassphrase: passphrase) - let address = Crypto.address(fromPublicKey: keys.publicKeyString) + let keys: KeyPair! = try Crypto.keyPair(fromPassphrase: passphrase) + let address: String! = Crypto.address(fromPublicKey: keys.publicKeyString) let account = LskAccount(keys: keys, address: address, balance: BigUInt(0), balanceString: "0") self.account = account // print(address) @@ -98,6 +99,7 @@ class AdamantLskApiService: LskApiService { } } } + */ } func createTransaction(toAddress address: String, amount: Double, completion: @escaping (ApiServiceResult) -> Void) { diff --git a/Adamant/SwinjectDependencies.swift b/Adamant/SwinjectDependencies.swift index b95787b3d..516b5c073 100644 --- a/Adamant/SwinjectDependencies.swift +++ b/Adamant/SwinjectDependencies.swift @@ -15,10 +15,7 @@ extension Container { // MARK: - Standalone services // MARK: AdamantCore self.register(AdamantCore.self) { _ in - let core = JSAdamantCore() - core.loadJs(from: AdamantResources.jsCore, queue: DispatchQueue.global(qos: .background)) { result in - if case .error(let e) = result { fatalError(e.localizedDescription) } - } + let core = NativeAdamantCore() return core }.inObjectScope(.container) diff --git a/Adamant/Utilities/Crypto.swift b/Adamant/Utilities/Crypto.swift new file mode 100644 index 000000000..2e83df735 --- /dev/null +++ b/Adamant/Utilities/Crypto.swift @@ -0,0 +1,273 @@ +// +// Crypto.swift +// Adamant +// +// Created by Anton Boyarkin on 01/08/2018. +// Copyright © 2018 Adamant. All rights reserved. +// + +import Foundation +import libsodium +import CryptoSwift +import ByteBackpacker + +public typealias Bytes = Array + +public struct Crypto { + public static let sign = Sign() + public static let box = Box() + public static let secretBox = SecretBox() + public static let ed2Curve = ED2Curve() +} + +public struct Sign { + public var SignBytes: Int { return Int(crypto_sign_bytes()) } + public var PublicKeyBytes: Int { return Int(crypto_sign_publickeybytes()) } + public var SecretKeyBytes: Int { return Int(crypto_sign_secretkeybytes()) } + + public func keypair(from seed: Bytes) -> (publicKey: Bytes, privateKey: Bytes)? { + var publicKey = Bytes(count: PublicKeyBytes) + var privateKey = Bytes(count: SecretKeyBytes) + + guard .SUCCESS == crypto_sign_seed_keypair( + &publicKey, + &privateKey, + seed + ).exitCode else { return nil } + + return (publicKey: publicKey, privateKey: privateKey) + } + + public func signature(message: Bytes, secretKey: Bytes) -> Bytes? { + guard secretKey.count == SecretKeyBytes else { return nil } + var signature = Array(count: SignBytes) + + guard .SUCCESS == crypto_sign_detached ( + &signature, + nil, + message, UInt64(message.count), + secretKey + ).exitCode else { return nil } + + return signature + } +} + +public struct ED2Curve { + private var KeyBytes: Int { return Int(crypto_scalarmult_curve25519_bytes()) } + + public func publicKey(_ key: Bytes) -> Bytes? { + var publicKey = Bytes(count: KeyBytes) + + guard .SUCCESS == crypto_sign_ed25519_pk_to_curve25519( + &publicKey, + key + ).exitCode else { return nil } + + return publicKey + } + + public func privateKey(_ key: Bytes) -> Bytes? { + var privateKey = Bytes(count: KeyBytes) + + guard .SUCCESS == crypto_sign_ed25519_sk_to_curve25519( + &privateKey, + key + ).exitCode else { return nil } + + return privateKey + } +} + +public struct Box: NonceGenerator { + public var MacBytes: Int { return Int(crypto_box_macbytes()) } + public var NonceBytes: Int { return Int(crypto_box_noncebytes()) } + public var PublicKeyBytes: Int { return Int(crypto_box_publickeybytes()) } + public var SecretKeyBytes: Int { return Int(crypto_box_secretkeybytes()) } + + public func seal(message: Bytes, recipientPublicKey: Bytes, senderSecretKey: Bytes) -> (authenticatedCipherText: Bytes, nonce: Bytes)? { + guard recipientPublicKey.count == PublicKeyBytes, + senderSecretKey.count == SecretKeyBytes + else { return nil } + + var authenticatedCipherText = Bytes(count: message.count + MacBytes) + let nonce = self.nonce() + + guard .SUCCESS == crypto_box_easy( + &authenticatedCipherText, + message, + CUnsignedLongLong(message.count), + nonce, + recipientPublicKey, + senderSecretKey + ).exitCode else { return nil } + + return (authenticatedCipherText: authenticatedCipherText, nonce: nonce) + } + + public func open(authenticatedCipherText: Bytes, senderPublicKey: Bytes, recipientSecretKey: Bytes, nonce: Bytes) -> Bytes? { + guard nonce.count == NonceBytes, + authenticatedCipherText.count >= MacBytes, + senderPublicKey.count == PublicKeyBytes, + recipientSecretKey.count == SecretKeyBytes + else { return nil } + + var message = Bytes(count: authenticatedCipherText.count - MacBytes) + + guard .SUCCESS == crypto_box_open_easy( + &message, + authenticatedCipherText, UInt64(authenticatedCipherText.count), + nonce, + senderPublicKey, + recipientSecretKey + ).exitCode else { return nil } + + return message + } +} + +public struct SecretBox: NonceGenerator { + public var MacBytes: Int { return Int(crypto_secretbox_macbytes()) } + public var NonceBytes: Int { return Int(crypto_secretbox_noncebytes()) } + public var KeyBytes: Int { return Int(crypto_secretbox_keybytes()) } + + public func seal(message: Bytes, secretKey: Bytes) -> (authenticatedCipherText: Bytes, nonce: Bytes)? { + guard secretKey.count == KeyBytes else { return nil } + var authenticatedCipherText = Bytes(count: message.count + MacBytes) + let nonce = self.nonce() + + guard .SUCCESS == crypto_secretbox_easy ( + &authenticatedCipherText, + message, UInt64(message.count), + nonce, + secretKey + ).exitCode else { return nil } + + return (authenticatedCipherText: authenticatedCipherText, nonce: nonce) + } + + public func open(authenticatedCipherText: Bytes, secretKey: Bytes, nonce: Bytes) -> Bytes? { + guard authenticatedCipherText.count >= MacBytes else { return nil } + var message = Bytes(count: authenticatedCipherText.count - MacBytes) + + guard .SUCCESS == crypto_secretbox_open_easy ( + &message, + authenticatedCipherText, UInt64(authenticatedCipherText.count), + nonce, + secretKey + ).exitCode else { return nil } + + return message + } +} + +public protocol NonceGenerator { + var NonceBytes: Int { get } +} + +extension NonceGenerator { + /// Generates a random nonce. + public func nonce() -> Bytes { + var nonce = Bytes(count: NonceBytes) + randombytes_buf(&nonce, NonceBytes) + return nonce + } +} + +// MARK:- Helpers +extension Data { + func toString() -> String? { + return String(data: self, encoding: .utf8) + } +} + +extension Array where Element == UInt8 { + init (count bytes: Int) { + self.init(repeating: 0, count: bytes) + } + + public var utf8String: String? { + return String(data: Data(bytes: self), encoding: .utf8) + } + + func toData() -> Data { + return Data(bytes: self) + } +} + +extension ArraySlice where Element == UInt8 { + var bytes: Bytes { return Bytes(self) } +} + +extension String { + var bytes: Bytes { return Bytes(self.utf8) } + + func hexBytes() -> [UInt8] { + return (0.. [String: Any]? { + if let data = self.data(using: .utf8) { + do { + return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + } catch { + print(error.localizedDescription) + } + } + return nil + } + + func matches(for regex: String) -> [String] { + do { + let regex = try NSRegularExpression(pattern: regex) + let results = regex.matches(in: self, + range: NSRange(self.startIndex..., in: self)) + return results.map { + String(self[Range($0.range, in: self)!]) + } + } catch let error { + print("invalid regex: \(error.localizedDescription)") + return [] + } + } + + subscript (i: Int) -> Character + { + return self[index(startIndex, offsetBy:i)] + } + + static func random(length: Int = 32, alphabet: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String + { + let upperBound = UInt32(alphabet.count) + return String((0.. Character in + return alphabet[Int(arc4random_uniform(upperBound))] + }) + } +} + +enum ExitCode { + case SUCCESS + case FAILURE + + init (from int: Int32) { + switch int { + case 0: self = .SUCCESS + default: self = .FAILURE + } + } +} + +extension Int32 { + var exitCode: ExitCode { return ExitCode(from: self) } +} + +extension Sequence where Self.Element == UInt8 { + internal func hexString() -> String { + return map { String(format: "%02hhx", $0) }.joined() + } +} diff --git a/Adamant/Utilities/Mnemonic.swift b/Adamant/Utilities/Mnemonic.swift new file mode 100644 index 000000000..15dab5a4b --- /dev/null +++ b/Adamant/Utilities/Mnemonic.swift @@ -0,0 +1,2120 @@ +// +// Mnemonic.swift +// Adamant +// +// Created by Anton Boyarkin on 01/08/2018. +// Copyright © 2018 Adamant. All rights reserved. +// + +import Foundation +import CryptoSwift + +public struct Mnemonic { + + public static func generate() throws -> [String] { + let byteCount = 16 + var bytes = Data(count: byteCount) + let status = bytes.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, byteCount, $0) } + guard status == errSecSuccess else { throw MnemonicError.randomBytesError } + return generate(entropy: bytes) + } + + static func generate(entropy : Data) -> [String] { + let list = WordList.english + var bin = String(entropy.flatMap { ("00000000" + String($0, radix:2)).suffix(8) }) + + let hash = entropy.sha256() + let bits = entropy.count * 8 + let cs = bits / 32 + + let hashbits = String(hash.flatMap { ("00000000" + String($0, radix:2)).suffix(8) }) + let checksum = String(hashbits.prefix(cs)) + bin += checksum + + var mnemonic = [String]() + for i in 0..<(bin.count / 11) { + let wi = Int(bin[bin.index(bin.startIndex, offsetBy: i * 11).. [UInt8]? { + let mnemonic = m.joined(separator: " ") + let salt = ("mnemonic" + passphrase) + + return seed(passphrase: mnemonic, salt: salt) + } + + public static func seed(passphrase: String, salt: String = "mnemonic") -> [UInt8]? { + let password = passphrase.decomposedStringWithCompatibilityMapping + let salt = salt.decomposedStringWithCompatibilityMapping + + if let seed = try? PKCS5.PBKDF2(password: password.bytes, salt: salt.bytes, iterations: 2048, keyLength: 64, variant: HMAC.Variant.sha512).calculate() { + return seed + } else { + return nil + } + } +} + +public enum MnemonicError : Error { + case randomBytesError +} + +class WordList { + static var english: [String.SubSequence] = { + let words = + """ + abandon + ability + able + about + above + absent + absorb + abstract + absurd + abuse + access + accident + account + accuse + achieve + acid + acoustic + acquire + across + act + action + actor + actress + actual + adapt + add + addict + address + adjust + admit + adult + advance + advice + aerobic + affair + afford + afraid + again + age + agent + agree + ahead + aim + air + airport + aisle + alarm + album + alcohol + alert + alien + all + alley + allow + almost + alone + alpha + already + also + alter + always + amateur + amazing + among + amount + amused + analyst + anchor + ancient + anger + angle + angry + animal + ankle + announce + annual + another + answer + antenna + antique + anxiety + any + apart + apology + appear + apple + approve + april + arch + arctic + area + arena + argue + arm + armed + armor + army + around + arrange + arrest + arrive + arrow + art + artefact + artist + artwork + ask + aspect + assault + asset + assist + assume + asthma + athlete + atom + attack + attend + attitude + attract + auction + audit + august + aunt + author + auto + autumn + average + avocado + avoid + awake + aware + away + awesome + awful + awkward + axis + baby + bachelor + bacon + badge + bag + balance + balcony + ball + bamboo + banana + banner + bar + barely + bargain + barrel + base + basic + basket + battle + beach + bean + beauty + because + become + beef + before + begin + behave + behind + believe + below + belt + bench + benefit + best + betray + better + between + beyond + bicycle + bid + bike + bind + biology + bird + birth + bitter + black + blade + blame + blanket + blast + bleak + bless + blind + blood + blossom + blouse + blue + blur + blush + board + boat + body + boil + bomb + bone + bonus + book + boost + border + boring + borrow + boss + bottom + bounce + box + boy + bracket + brain + brand + brass + brave + bread + breeze + brick + bridge + brief + bright + bring + brisk + broccoli + broken + bronze + broom + brother + brown + brush + bubble + buddy + budget + buffalo + build + bulb + bulk + bullet + bundle + bunker + burden + burger + burst + bus + business + busy + butter + buyer + buzz + cabbage + cabin + cable + cactus + cage + cake + call + calm + camera + camp + can + canal + cancel + candy + cannon + canoe + canvas + canyon + capable + capital + captain + car + carbon + card + cargo + carpet + carry + cart + case + cash + casino + castle + casual + cat + catalog + catch + category + cattle + caught + cause + caution + cave + ceiling + celery + cement + census + century + cereal + certain + chair + chalk + champion + change + chaos + chapter + charge + chase + chat + cheap + check + cheese + chef + cherry + chest + chicken + chief + child + chimney + choice + choose + chronic + chuckle + chunk + churn + cigar + cinnamon + circle + citizen + city + civil + claim + clap + clarify + claw + clay + clean + clerk + clever + click + client + cliff + climb + clinic + clip + clock + clog + close + cloth + cloud + clown + club + clump + cluster + clutch + coach + coast + coconut + code + coffee + coil + coin + collect + color + column + combine + come + comfort + comic + common + company + concert + conduct + confirm + congress + connect + consider + control + convince + cook + cool + copper + copy + coral + core + corn + correct + cost + cotton + couch + country + couple + course + cousin + cover + coyote + crack + cradle + craft + cram + crane + crash + crater + crawl + crazy + cream + credit + creek + crew + cricket + crime + crisp + critic + crop + cross + crouch + crowd + crucial + cruel + cruise + crumble + crunch + crush + cry + crystal + cube + culture + cup + cupboard + curious + current + curtain + curve + cushion + custom + cute + cycle + dad + damage + damp + dance + danger + daring + dash + daughter + dawn + day + deal + debate + debris + decade + december + decide + decline + decorate + decrease + deer + defense + define + defy + degree + delay + deliver + demand + demise + denial + dentist + deny + depart + depend + deposit + depth + deputy + derive + describe + desert + design + desk + despair + destroy + detail + detect + develop + device + devote + diagram + dial + diamond + diary + dice + diesel + diet + differ + digital + dignity + dilemma + dinner + dinosaur + direct + dirt + disagree + discover + disease + dish + dismiss + disorder + display + distance + divert + divide + divorce + dizzy + doctor + document + dog + doll + dolphin + domain + donate + donkey + donor + door + dose + double + dove + draft + dragon + drama + drastic + draw + dream + dress + drift + drill + drink + drip + drive + drop + drum + dry + duck + dumb + dune + during + dust + dutch + duty + dwarf + dynamic + eager + eagle + early + earn + earth + easily + east + easy + echo + ecology + economy + edge + edit + educate + effort + egg + eight + either + elbow + elder + electric + elegant + element + elephant + elevator + elite + else + embark + embody + embrace + emerge + emotion + employ + empower + empty + enable + enact + end + endless + endorse + enemy + energy + enforce + engage + engine + enhance + enjoy + enlist + enough + enrich + enroll + ensure + enter + entire + entry + envelope + episode + equal + equip + era + erase + erode + erosion + error + erupt + escape + essay + essence + estate + eternal + ethics + evidence + evil + evoke + evolve + exact + example + excess + exchange + excite + exclude + excuse + execute + exercise + exhaust + exhibit + exile + exist + exit + exotic + expand + expect + expire + explain + expose + express + extend + extra + eye + eyebrow + fabric + face + faculty + fade + faint + faith + fall + false + fame + family + famous + fan + fancy + fantasy + farm + fashion + fat + fatal + father + fatigue + fault + favorite + feature + february + federal + fee + feed + feel + female + fence + festival + fetch + fever + few + fiber + fiction + field + figure + file + film + filter + final + find + fine + finger + finish + fire + firm + first + fiscal + fish + fit + fitness + fix + flag + flame + flash + flat + flavor + flee + flight + flip + float + flock + floor + flower + fluid + flush + fly + foam + focus + fog + foil + fold + follow + food + foot + force + forest + forget + fork + fortune + forum + forward + fossil + foster + found + fox + fragile + frame + frequent + fresh + friend + fringe + frog + front + frost + frown + frozen + fruit + fuel + fun + funny + furnace + fury + future + gadget + gain + galaxy + gallery + game + gap + garage + garbage + garden + garlic + garment + gas + gasp + gate + gather + gauge + gaze + general + genius + genre + gentle + genuine + gesture + ghost + giant + gift + giggle + ginger + giraffe + girl + give + glad + glance + glare + glass + glide + glimpse + globe + gloom + glory + glove + glow + glue + goat + goddess + gold + good + goose + gorilla + gospel + gossip + govern + gown + grab + grace + grain + grant + grape + grass + gravity + great + green + grid + grief + grit + grocery + group + grow + grunt + guard + guess + guide + guilt + guitar + gun + gym + habit + hair + half + hammer + hamster + hand + happy + harbor + hard + harsh + harvest + hat + have + hawk + hazard + head + health + heart + heavy + hedgehog + height + hello + helmet + help + hen + hero + hidden + high + hill + hint + hip + hire + history + hobby + hockey + hold + hole + holiday + hollow + home + honey + hood + hope + horn + horror + horse + hospital + host + hotel + hour + hover + hub + huge + human + humble + humor + hundred + hungry + hunt + hurdle + hurry + hurt + husband + hybrid + ice + icon + idea + identify + idle + ignore + ill + illegal + illness + image + imitate + immense + immune + impact + impose + improve + impulse + inch + include + income + increase + index + indicate + indoor + industry + infant + inflict + inform + inhale + inherit + initial + inject + injury + inmate + inner + innocent + input + inquiry + insane + insect + inside + inspire + install + intact + interest + into + invest + invite + involve + iron + island + isolate + issue + item + ivory + jacket + jaguar + jar + jazz + jealous + jeans + jelly + jewel + job + join + joke + journey + joy + judge + juice + jump + jungle + junior + junk + just + kangaroo + keen + keep + ketchup + key + kick + kid + kidney + kind + kingdom + kiss + kit + kitchen + kite + kitten + kiwi + knee + knife + knock + know + lab + label + labor + ladder + lady + lake + lamp + language + laptop + large + later + latin + laugh + laundry + lava + law + lawn + lawsuit + layer + lazy + leader + leaf + learn + leave + lecture + left + leg + legal + legend + leisure + lemon + lend + length + lens + leopard + lesson + letter + level + liar + liberty + library + license + life + lift + light + like + limb + limit + link + lion + liquid + list + little + live + lizard + load + loan + lobster + local + lock + logic + lonely + long + loop + lottery + loud + lounge + love + loyal + lucky + luggage + lumber + lunar + lunch + luxury + lyrics + machine + mad + magic + magnet + maid + mail + main + major + make + mammal + man + manage + mandate + mango + mansion + manual + maple + marble + march + margin + marine + market + marriage + mask + mass + master + match + material + math + matrix + matter + maximum + maze + meadow + mean + measure + meat + mechanic + medal + media + melody + melt + member + memory + mention + menu + mercy + merge + merit + merry + mesh + message + metal + method + middle + midnight + milk + million + mimic + mind + minimum + minor + minute + miracle + mirror + misery + miss + mistake + mix + mixed + mixture + mobile + model + modify + mom + moment + monitor + monkey + monster + month + moon + moral + more + morning + mosquito + mother + motion + motor + mountain + mouse + move + movie + much + muffin + mule + multiply + muscle + museum + mushroom + music + must + mutual + myself + mystery + myth + naive + name + napkin + narrow + nasty + nation + nature + near + neck + need + negative + neglect + neither + nephew + nerve + nest + net + network + neutral + never + news + next + nice + night + noble + noise + nominee + noodle + normal + north + nose + notable + note + nothing + notice + novel + now + nuclear + number + nurse + nut + oak + obey + object + oblige + obscure + observe + obtain + obvious + occur + ocean + october + odor + off + offer + office + often + oil + okay + old + olive + olympic + omit + once + one + onion + online + only + open + opera + opinion + oppose + option + orange + orbit + orchard + order + ordinary + organ + orient + original + orphan + ostrich + other + outdoor + outer + output + outside + oval + oven + over + own + owner + oxygen + oyster + ozone + pact + paddle + page + pair + palace + palm + panda + panel + panic + panther + paper + parade + parent + park + parrot + party + pass + patch + path + patient + patrol + pattern + pause + pave + payment + peace + peanut + pear + peasant + pelican + pen + penalty + pencil + people + pepper + perfect + permit + person + pet + phone + photo + phrase + physical + piano + picnic + picture + piece + pig + pigeon + pill + pilot + pink + pioneer + pipe + pistol + pitch + pizza + place + planet + plastic + plate + play + please + pledge + pluck + plug + plunge + poem + poet + point + polar + pole + police + pond + pony + pool + popular + portion + position + possible + post + potato + pottery + poverty + powder + power + practice + praise + predict + prefer + prepare + present + pretty + prevent + price + pride + primary + print + priority + prison + private + prize + problem + process + produce + profit + program + project + promote + proof + property + prosper + protect + proud + provide + public + pudding + pull + pulp + pulse + pumpkin + punch + pupil + puppy + purchase + purity + purpose + purse + push + put + puzzle + pyramid + quality + quantum + quarter + question + quick + quit + quiz + quote + rabbit + raccoon + race + rack + radar + radio + rail + rain + raise + rally + ramp + ranch + random + range + rapid + rare + rate + rather + raven + raw + razor + ready + real + reason + rebel + rebuild + recall + receive + recipe + record + recycle + reduce + reflect + reform + refuse + region + regret + regular + reject + relax + release + relief + rely + remain + remember + remind + remove + render + renew + rent + reopen + repair + repeat + replace + report + require + rescue + resemble + resist + resource + response + result + retire + retreat + return + reunion + reveal + review + reward + rhythm + rib + ribbon + rice + rich + ride + ridge + rifle + right + rigid + ring + riot + ripple + risk + ritual + rival + river + road + roast + robot + robust + rocket + romance + roof + rookie + room + rose + rotate + rough + round + route + royal + rubber + rude + rug + rule + run + runway + rural + sad + saddle + sadness + safe + sail + salad + salmon + salon + salt + salute + same + sample + sand + satisfy + satoshi + sauce + sausage + save + say + scale + scan + scare + scatter + scene + scheme + school + science + scissors + scorpion + scout + scrap + screen + script + scrub + sea + search + season + seat + second + secret + section + security + seed + seek + segment + select + sell + seminar + senior + sense + sentence + series + service + session + settle + setup + seven + shadow + shaft + shallow + share + shed + shell + sheriff + shield + shift + shine + ship + shiver + shock + shoe + shoot + shop + short + shoulder + shove + shrimp + shrug + shuffle + shy + sibling + sick + side + siege + sight + sign + silent + silk + silly + silver + similar + simple + since + sing + siren + sister + situate + six + size + skate + sketch + ski + skill + skin + skirt + skull + slab + slam + sleep + slender + slice + slide + slight + slim + slogan + slot + slow + slush + small + smart + smile + smoke + smooth + snack + snake + snap + sniff + snow + soap + soccer + social + sock + soda + soft + solar + soldier + solid + solution + solve + someone + song + soon + sorry + sort + soul + sound + soup + source + south + space + spare + spatial + spawn + speak + special + speed + spell + spend + sphere + spice + spider + spike + spin + spirit + split + spoil + sponsor + spoon + sport + spot + spray + spread + spring + spy + square + squeeze + squirrel + stable + stadium + staff + stage + stairs + stamp + stand + start + state + stay + steak + steel + stem + step + stereo + stick + still + sting + stock + stomach + stone + stool + story + stove + strategy + street + strike + strong + struggle + student + stuff + stumble + style + subject + submit + subway + success + such + sudden + suffer + sugar + suggest + suit + summer + sun + sunny + sunset + super + supply + supreme + sure + surface + surge + surprise + surround + survey + suspect + sustain + swallow + swamp + swap + swarm + swear + sweet + swift + swim + swing + switch + sword + symbol + symptom + syrup + system + table + tackle + tag + tail + talent + talk + tank + tape + target + task + taste + tattoo + taxi + teach + team + tell + ten + tenant + tennis + tent + term + test + text + thank + that + theme + then + theory + there + they + thing + this + thought + three + thrive + throw + thumb + thunder + ticket + tide + tiger + tilt + timber + time + tiny + tip + tired + tissue + title + toast + tobacco + today + toddler + toe + together + toilet + token + tomato + tomorrow + tone + tongue + tonight + tool + tooth + top + topic + topple + torch + tornado + tortoise + toss + total + tourist + toward + tower + town + toy + track + trade + traffic + tragic + train + transfer + trap + trash + travel + tray + treat + tree + trend + trial + tribe + trick + trigger + trim + trip + trophy + trouble + truck + true + truly + trumpet + trust + truth + try + tube + tuition + tumble + tuna + tunnel + turkey + turn + turtle + twelve + twenty + twice + twin + twist + two + type + typical + ugly + umbrella + unable + unaware + uncle + uncover + under + undo + unfair + unfold + unhappy + uniform + unique + unit + universe + unknown + unlock + until + unusual + unveil + update + upgrade + uphold + upon + upper + upset + urban + urge + usage + use + used + useful + useless + usual + utility + vacant + vacuum + vague + valid + valley + valve + van + vanish + vapor + various + vast + vault + vehicle + velvet + vendor + venture + venue + verb + verify + version + very + vessel + veteran + viable + vibrant + vicious + victory + video + view + village + vintage + violin + virtual + virus + visa + visit + visual + vital + vivid + vocal + voice + void + volcano + volume + vote + voyage + wage + wagon + wait + walk + wall + walnut + want + warfare + warm + warrior + wash + wasp + waste + water + wave + way + wealth + weapon + wear + weasel + weather + web + wedding + weekend + weird + welcome + west + wet + whale + what + wheat + wheel + when + where + whip + whisper + wide + width + wife + wild + will + win + window + wine + wing + wink + winner + winter + wire + wisdom + wise + wish + witness + wolf + woman + wonder + wood + wool + word + work + world + worry + worth + wrap + wreck + wrestle + wrist + write + wrong + yard + year + yellow + you + young + youth + zebra + zero + zone + zoo + """ + return words.split(separator: "\n") + }() +} diff --git a/Adamant/Wallets/Lisk/LskTransactionsViewController.swift b/Adamant/Wallets/Lisk/LskTransactionsViewController.swift index 804f42227..f549219d4 100644 --- a/Adamant/Wallets/Lisk/LskTransactionsViewController.swift +++ b/Adamant/Wallets/Lisk/LskTransactionsViewController.swift @@ -63,7 +63,7 @@ class LskTransactionsViewController: TransactionsListViewControllerBase { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) - let transaction = transactions[indexPath.row] +// let transaction = transactions[indexPath.row] guard let controller = router.get(scene: AdamantScene.Wallets.Ethereum.transactionDetails) as? TransactionDetailsViewControllerBase else { return @@ -79,7 +79,7 @@ class LskTransactionsViewController: TransactionsListViewControllerBase { return UITableViewCell(style: .default, reuseIdentifier: "cell") } - let transaction = transactions[indexPath.row] +// let transaction = transactions[indexPath.row] cell.accessoryType = .disclosureIndicator diff --git a/Adamant/Services/JSAdamantCore.swift b/AdamantTests/Core/JSAdamantCore.swift similarity index 97% rename from Adamant/Services/JSAdamantCore.swift rename to AdamantTests/Core/JSAdamantCore.swift index 12d17bb9d..e8895c390 100644 --- a/Adamant/Services/JSAdamantCore.swift +++ b/AdamantTests/Core/JSAdamantCore.swift @@ -8,6 +8,7 @@ import Foundation import JavaScriptCore +@testable import Adamant // MARK: - Functions private enum JsFunction: String { @@ -36,6 +37,14 @@ enum AdamantCoreError: Error { /// You must load JavaScript before calling any methods. class JSAdamantCore : AdamantCore { + func encodeValue(_ value: [String : Any], privateKey: String) -> (message: String, nonce: String)? { + return nil + } + + func decodeValue(rawMessage: String, rawNonce: String, privateKey: String) -> String? { + return nil + } + enum Result { case success case error(error: Error) diff --git a/AdamantTests/JSAdamantCoreTests.swift b/AdamantTests/Core/JSAdamantCoreTests.swift similarity index 93% rename from AdamantTests/JSAdamantCoreTests.swift rename to AdamantTests/Core/JSAdamantCoreTests.swift index 89da08592..7ccb7eae4 100644 --- a/AdamantTests/JSAdamantCoreTests.swift +++ b/AdamantTests/Core/JSAdamantCoreTests.swift @@ -15,7 +15,7 @@ class JSAdamantCoreTests: XCTestCase { override func setUp() { super.setUp() - guard let jsCore = Bundle.main.url(forResource: "adamant-core", withExtension: "js") else { + guard let jsCore = Bundle(for: type(of: self)).url(forResource: "adamant-core", withExtension: "js") else { fatalError("Can't load system resources!") } @@ -56,17 +56,17 @@ class JSAdamantCoreTests: XCTestCase { func testSignTransaction() { let transaction = NormalizedTransaction(type: TransactionType.send, - amount: 50000000, + amount: 60000000, senderPublicKey: "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f", requesterPublicKey: nil, - timestamp: 11325525, - recipientId: "U48484848484848484848484", + timestamp: 13131802, + recipientId: "U7038846184609740192", asset: TransactionAsset()) let senderId = "U2279741505997340299" let keypair = Keypair(publicKey: "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f", privateKey: "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f") - let signature = "cf2718a77527016ae1a847c190b0986e75fdc57926afc5aaebfa16fb7cb2cb64690b79cab9230f3328695770cf36370cc5be2b323419873081aa351d32b5db05" + let signature = "cdde6db8cfa9ebbca67f4625b0fdded5a130f01b4300423c4446e7b8ed79f95447be8b4dfd5d67b849d47bd9d834ddff3942499d350673e129f15ba2c1005807" let freshSignature = core.sign(transaction: transaction, senderId: senderId, keypair: keypair) XCTAssertEqual(signature, freshSignature) diff --git a/Adamant/Helpers/JSModels.swift b/AdamantTests/Core/JSModels.swift similarity index 99% rename from Adamant/Helpers/JSModels.swift rename to AdamantTests/Core/JSModels.swift index 6007364f1..ba3b3afce 100644 --- a/Adamant/Helpers/JSModels.swift +++ b/AdamantTests/Core/JSModels.swift @@ -8,7 +8,7 @@ import Foundation import JavaScriptCore - +@testable import Adamant // MARK: Keypair diff --git a/AdamantTests/Core/NativeCoreTests.swift b/AdamantTests/Core/NativeCoreTests.swift new file mode 100644 index 000000000..b673f41d9 --- /dev/null +++ b/AdamantTests/Core/NativeCoreTests.swift @@ -0,0 +1,197 @@ +// +// NativeCoreTests.swift +// AdamantTests +// +// Created by Anokhov Pavel on 11/11/2018. +// Copyright © 2018 Adamant. All rights reserved. +// + +import XCTest +@testable import Adamant + +class NativeCoreTests: XCTestCase { + var core: AdamantCore! + + override func setUp() { + super.setUp() + + core = NativeAdamantCore() + } + + func testHashForPassphrase() { + let passphrase = "process gospel angry height between flat always clock suit refuse shove verb" + let hash = "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab" + + let freshHash = core.createHashFor(passphrase: passphrase) + XCTAssertEqual(hash, freshHash) + } + + func testKeypairForPassphrase() { + let passphrase = "process gospel angry height between flat always clock suit refuse shove verb" + let publicKey = "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let privateKey = "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + + let freshKeypair = core.createKeypairFor(passphrase: passphrase) + XCTAssertEqual(publicKey, freshKeypair?.publicKey) + XCTAssertEqual(privateKey, freshKeypair?.privateKey) + } + + func testGeneratePassphrase() { + let passphrase = core.generateNewPassphrase() + + XCTAssert(passphrase.split(separator: " ").count == 12) + } + + func testSignTransaction() { + let transaction = NormalizedTransaction(type: TransactionType.send, + amount: 60000000, + senderPublicKey: "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f", + requesterPublicKey: nil, + timestamp: 13131802, + recipientId: "U7038846184609740192", + asset: TransactionAsset()) + let senderId = "U2279741505997340299" + let keypair = Keypair(publicKey: "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f", + privateKey: "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f") + + let signature = "cdde6db8cfa9ebbca67f4625b0fdded5a130f01b4300423c4446e7b8ed79f95447be8b4dfd5d67b849d47bd9d834ddff3942499d350673e129f15ba2c1005807" + + let freshSignature = core.sign(transaction: transaction, senderId: senderId, keypair: keypair) + XCTAssertEqual(signature, freshSignature) + } + + func testEncodeMessage() { + let message = "common" + let aPublicKey = "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let aPrivateKey = "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let bPublicKey = "9f895a201fd92cc60ef02d2117d53f00dc2981903cb64b2f214777269b882209" + let bPrivateKey = "e91ee8e6a23ac5ff9452a15a3fbd14098dc2c6a5abf6b12464b09eb033580b6d9f895a201fd92cc60ef02d2117d53f00dc2981903cb64b2f214777269b882209" + + guard let encoded = core.encodeMessage(message, recipientPublicKey: bPublicKey, privateKey: aPrivateKey) else { + XCTFail() + return + } + + guard let decoded = core.decodeMessage(rawMessage: encoded.message, rawNonce: encoded.nonce, senderPublicKey: aPublicKey, privateKey: bPrivateKey) else { + XCTFail() + return + } + + XCTAssertEqual(message, decoded) + } + + func testDecodeMessage() { + let publicKey = "9f895a201fd92cc60ef02d2117d53f00dc2981903cb64b2f214777269b882209" + let privateKey = "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let message = "09af1ce7e5ed484ddca3c6d1410cbf4f793ea19210e7" + let nonce = "31caaee2d35dcbd8b614e9d6bf6095393cb5baed259e7e37" + let decodedMessage = "common" + + let freshMessage = core.decodeMessage(rawMessage: message, rawNonce: nonce, senderPublicKey: publicKey, privateKey: privateKey) + + XCTAssertEqual(freshMessage, decodedMessage) + } + + // MARK: - JS to Native + + func testDecodeJsEncodedMessage() { + let message = "common" + let aPublicKey = "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let aPrivateKey = "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let bPublicKey = "9f895a201fd92cc60ef02d2117d53f00dc2981903cb64b2f214777269b882209" + let bPrivateKey = "e91ee8e6a23ac5ff9452a15a3fbd14098dc2c6a5abf6b12464b09eb033580b6d9f895a201fd92cc60ef02d2117d53f00dc2981903cb64b2f214777269b882209" + + guard let js = Bundle(for: type(of: self)).url(forResource: "adamant-core", withExtension: "js") else { + fatalError("Can't load system resources!") + } + + let jsCore = JSAdamantCore() + jsCore.loadJs(from: js, queue: DispatchQueue.global(qos: .utility)) { (result) in + if case .error = result { + fatalError() + } + } + + // Encode with JS + guard let encoded = jsCore.encodeMessage(message, recipientPublicKey: bPublicKey, privateKey: aPrivateKey) else { + XCTFail() + return + } + + // Decode with Native + guard let decoded = core.decodeMessage(rawMessage: encoded.message, rawNonce: encoded.nonce, senderPublicKey: aPublicKey, privateKey: bPrivateKey) else { + XCTFail() + return + } + + XCTAssertEqual(message, decoded) + } + + func testEncodeMessageForJs() { + let message = "common" + let aPublicKey = "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let aPrivateKey = "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f" + let bPublicKey = "9f895a201fd92cc60ef02d2117d53f00dc2981903cb64b2f214777269b882209" + let bPrivateKey = "e91ee8e6a23ac5ff9452a15a3fbd14098dc2c6a5abf6b12464b09eb033580b6d9f895a201fd92cc60ef02d2117d53f00dc2981903cb64b2f214777269b882209" + + guard let js = Bundle(for: type(of: self)).url(forResource: "adamant-core", withExtension: "js") else { + fatalError("Can't load system resources!") + } + + let jsCore = JSAdamantCore() + jsCore.loadJs(from: js, queue: DispatchQueue.global(qos: .utility)) { (result) in + if case .error = result { + fatalError() + } + } + + // Encode with native + guard let encoded = core.encodeMessage(message, recipientPublicKey: bPublicKey, privateKey: aPrivateKey) else { + XCTFail() + return + } + + // Decode with JS + guard let decoded = jsCore.decodeMessage(rawMessage: encoded.message, rawNonce: encoded.nonce, senderPublicKey: aPublicKey, privateKey: bPrivateKey) else { + XCTFail() + return + } + + XCTAssertEqual(message, decoded) + } + + // MARK: - Performance + + func testPerformanceHashForPassphrase() { + let passphrase = "process gospel angry height between flat always clock suit refuse shove verb" + + self.measure { + _ = core.createHashFor(passphrase: passphrase) + } + } + + func testPerformanceKeypairForPassphrase() { + let passphrase = "process gospel angry height between flat always clock suit refuse shove verb" + + self.measure { + _ = core.createKeypairFor(passphrase: passphrase) + } + } + + func testPerformanceSignTransaction() { + let transaction = NormalizedTransaction(type: TransactionType.send, + amount: 50000000, + senderPublicKey: "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f", + requesterPublicKey: nil, + timestamp: 11325525, + recipientId: "U48484848484848484848484", + asset: TransactionAsset()) + let senderId = "U2279741505997340299" + let keypair = Keypair(publicKey: "8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f", + privateKey: "9001490b166816af75a15a3e2b0174bfe3be3dfaa63147b4f780ed3ab90ffeab8007a01493bb4b21ec67265769898eb19514d9427bd7b701f96bc9880a6e209f") + + self.measure { + _ = core.sign(transaction: transaction, senderId: senderId, keypair: keypair) + } + } +} diff --git a/Adamant/Assets/adamant-core.js b/AdamantTests/Core/adamant-core.js similarity index 100% rename from Adamant/Assets/adamant-core.js rename to AdamantTests/Core/adamant-core.js diff --git a/Podfile b/Podfile index 840a39e40..987fd4c2f 100644 --- a/Podfile +++ b/Podfile @@ -6,8 +6,6 @@ target 'Adamant' do pod 'Alamofire' # Network pod 'KeychainAccess' # Keychain - pod 'RNCryptor' # Cryptor - pod 'CryptoSwift' # MD5 hash pod 'Swinject' # Dependency Injection pod 'ReachabilitySwift' # Network status pod 'Haring' # Markdown parser @@ -27,9 +25,14 @@ target 'Adamant' do pod 'EFQRCode' # QR generator pod 'QRCodeReader.swift' # QR reader - # Cryptos - pod 'libsodium' + # Crypto + pod 'RNCryptor' # Cryptor + pod 'CryptoSwift' # MD5 hash + pod 'libsodium' # Sodium crypto library pod 'web3swift' # ETH Web3 Swift Port pod 'Lisk', :git => 'https://github.com/boyarkin-anton/lisk-swift.git', :branch => 'dev' # LSK + + # Utility + pod 'ByteBackpacker' # Utility to pack value types into a Byte array end diff --git a/Podfile.lock b/Podfile.lock index b6287e532..356d827b4 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -2,6 +2,7 @@ PODS: - Alamofire (4.7.3) - BigInt (3.1.0): - SipHash (~> 1.2) + - ByteBackpacker (1.2.1) - CryptoSwift (0.12.0) - DateToolsSwift (4.0.0) - Ed25519 (1.1.0): @@ -59,6 +60,7 @@ PODS: DEPENDENCIES: - Alamofire + - ByteBackpacker - CryptoSwift - DateToolsSwift - EFQRCode @@ -84,6 +86,7 @@ SPEC REPOS: https://github.com/cocoapods/specs.git: - Alamofire - BigInt + - ByteBackpacker - CryptoSwift - DateToolsSwift - Ed25519 @@ -130,6 +133,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568 BigInt: 76b5dfdfa3e2e478d4ffdf161aeede5502e2742f + ByteBackpacker: df001da117faacdbf09b69a116ec480f6651c9ec CryptoSwift: 1c07ca50843dd48bc54e6ea53d7a4dba3b645716 DateToolsSwift: 875d97ff9e3a5d54abdd67a269b3f51c757b71ab Ed25519: d84c847d8ffbb2f6fec71479abbb8fa3dfe12578 @@ -159,6 +163,6 @@ SPEC CHECKSUMS: Swinject: 82cdb851f63f91bba974e3eca1d69780f2f7677e web3swift: 4895c765c9858eb4737ef222eb8643bb5fc7fdb3 -PODFILE CHECKSUM: 4a06595861816208b7a6aacfeded5a0b26245f53 +PODFILE CHECKSUM: 17981ca7dbf7440ef8c4e90c4b889b8aa510e6ad COCOAPODS: 1.6.0.beta.1