From 4660b41b7b60d47205b798bd378891ec416bc41f Mon Sep 17 00:00:00 2001 From: Lukas Korba Date: Thu, 10 Mar 2022 13:28:25 +0100 Subject: [PATCH] MnemonicSwift added to the project MnemonicSwift SPM added + implementation of the MnemonicSeedPhraseHandling protocol TCA syntax for the MnemonicSeedPhaseProvider swiftlint disable not needed anymore double space fixed --- secant.xcodeproj/project.pbxproj | 25 +++++- .../xcshareddata/swiftpm/Package.resolved | 18 ++++ .../MnemonicSeedPhraseHandling.swift | 41 --------- secant/MockedDependencies/Services.swift | 2 +- secant/Stubs/MockServices.swift | 38 +-------- secant/Util/MnemonicSeedPhraseProvider.swift | 83 +++++++++++++++++++ 6 files changed, 124 insertions(+), 83 deletions(-) delete mode 100644 secant/MockedDependencies/MnemonicSeedPhraseHandling.swift create mode 100644 secant/Util/MnemonicSeedPhraseProvider.swift diff --git a/secant.xcodeproj/project.pbxproj b/secant.xcodeproj/project.pbxproj index 4ede061..a4eb809 100644 --- a/secant.xcodeproj/project.pbxproj +++ b/secant.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ 0D2ACE8026C2C67100D62E3C /* Zboto.otf in Resources */ = {isa = PBXBuildFile; fileRef = 0D2ACE7F26C2C67100D62E3C /* Zboto.otf */; }; 0D354A0926D5A9D000315F45 /* Services.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D354A0626D5A9D000315F45 /* Services.swift */; }; 0D354A0A26D5A9D000315F45 /* KeyStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D354A0726D5A9D000315F45 /* KeyStoring.swift */; }; - 0D354A0B26D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D354A0826D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift */; }; 0D35CC46277A36E00074316A /* ScrollableWhenScaled.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D35CC45277A36E00074316A /* ScrollableWhenScaled.swift */; }; 0D3D04082728B3440032ABC1 /* RecoveryPhraseDisplayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D3D04072728B3440032ABC1 /* RecoveryPhraseDisplayView.swift */; }; 0D3D040A2728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D3D04092728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift */; }; @@ -81,6 +80,8 @@ 66A0807B271993C500118B79 /* OnboardingProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */; }; 66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */; }; 66DC733F271D88CC0053CBB6 /* StandardButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */; }; + 9E2AC0FF27D8EC120042AA47 /* MnemonicSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 9E2AC0FE27D8EC120042AA47 /* MnemonicSwift */; }; + 9E2AC10127D8EF0B0042AA47 /* MnemonicSeedPhraseProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2AC10027D8EF0B0042AA47 /* MnemonicSeedPhraseProvider.swift */; }; 9E2DF99C27CF704D00649636 /* ImportWalletStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99827CF704D00649636 /* ImportWalletStore.swift */; }; 9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */; }; 9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99B27CF704D00649636 /* ImportWalletView.swift */; }; @@ -145,7 +146,6 @@ 0D2ACE7F26C2C67100D62E3C /* Zboto.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Zboto.otf; sourceTree = ""; }; 0D354A0626D5A9D000315F45 /* Services.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Services.swift; sourceTree = ""; }; 0D354A0726D5A9D000315F45 /* KeyStoring.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyStoring.swift; sourceTree = ""; }; - 0D354A0826D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MnemonicSeedPhraseHandling.swift; sourceTree = ""; }; 0D35CC45277A36E00074316A /* ScrollableWhenScaled.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollableWhenScaled.swift; sourceTree = ""; }; 0D3D04072728B3440032ABC1 /* RecoveryPhraseDisplayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseDisplayView.swift; sourceTree = ""; }; 0D3D04092728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseDisplayStore.swift; sourceTree = ""; }; @@ -214,6 +214,7 @@ 66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingProgressIndicator.swift; sourceTree = ""; }; 66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationButtonStyle.swift; sourceTree = ""; }; 66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardButtonStyle.swift; sourceTree = ""; }; + 9E2AC10027D8EF0B0042AA47 /* MnemonicSeedPhraseProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicSeedPhraseProvider.swift; sourceTree = ""; }; 9E2DF99827CF704D00649636 /* ImportWalletStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletStore.swift; sourceTree = ""; }; 9E2DF99A27CF704D00649636 /* ImportSeedEditor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportSeedEditor.swift; sourceTree = ""; }; 9E2DF99B27CF704D00649636 /* ImportWalletView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletView.swift; sourceTree = ""; }; @@ -255,6 +256,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9E2AC0FF27D8EC120042AA47 /* MnemonicSwift in Frameworks */, 6654C73A2715A38000901167 /* ComposableArchitecture in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -296,7 +298,6 @@ isa = PBXGroup; children = ( 0D354A0726D5A9D000315F45 /* KeyStoring.swift */, - 0D354A0826D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift */, 0D354A0626D5A9D000315F45 /* Services.swift */, ); path = MockedDependencies; @@ -499,6 +500,7 @@ F9EEB8152742C2210032EEB8 /* WithStateBinding.swift */, F93673D52742CB840099C6AF /* Previews.swift */, 0D35CC45277A36E00074316A /* ScrollableWhenScaled.swift */, + 9E2AC10027D8EF0B0042AA47 /* MnemonicSeedPhraseProvider.swift */, ); path = Util; sourceTree = ""; @@ -855,6 +857,7 @@ name = "secant-testnet"; packageProductDependencies = ( 6654C7392715A38000901167 /* ComposableArchitecture */, + 9E2AC0FE27D8EC120042AA47 /* MnemonicSwift */, ); productName = secant; productReference = 0D4E7A0526B364170058B01E /* secant-testnet.app */; @@ -929,6 +932,7 @@ mainGroup = 0D4E79FC26B364170058B01E; packageReferences = ( 6654C7382715A38000901167 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */, + 9E2AC0FD27D8EC120042AA47 /* XCRemoteSwiftPackageReference "MnemonicSwift" */, ); productRefGroup = 0D4E7A0626B364170058B01E /* Products */; projectDirPath = ""; @@ -1047,7 +1051,6 @@ 0DACFA7F27208CE00039EEA5 /* Clamped.swift in Sources */, 0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidation.swift in Sources */, 9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */, - 0D354A0B26D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift in Sources */, 0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */, 6654C73E2715A41300901167 /* OnboardingStore.swift in Sources */, 9EBEF87A27CE369800B4F343 /* RecoveryPhraseTestPreambleView.swift in Sources */, @@ -1078,6 +1081,7 @@ 66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */, 0D1922F826BDEB3500052649 /* MockServices.swift in Sources */, 0D3D040A2728B3A10032ABC1 /* RecoveryPhraseDisplayStore.swift in Sources */, + 9E2AC10127D8EF0B0042AA47 /* MnemonicSeedPhraseProvider.swift in Sources */, 0D4E7A0B26B364170058B01E /* ContentView.swift in Sources */, 0D354A0926D5A9D000315F45 /* Services.swift in Sources */, 660558F7270C862F009D6954 /* Fonts+Generated.swift in Sources */, @@ -1448,6 +1452,14 @@ version = 0.28.1; }; }; + 9E2AC0FD27D8EC120042AA47 /* XCRemoteSwiftPackageReference "MnemonicSwift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/zcash-hackworks/MnemonicSwift"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1456,6 +1468,11 @@ package = 6654C7382715A38000901167 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */; productName = ComposableArchitecture; }; + 9E2AC0FE27D8EC120042AA47 /* MnemonicSwift */ = { + isa = XCSwiftPackageProductDependency; + package = 9E2AC0FD27D8EC120042AA47 /* XCRemoteSwiftPackageReference "MnemonicSwift" */; + productName = MnemonicSwift; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 0D4E79FD26B364170058B01E /* Project object */; diff --git a/secant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/secant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fb9ffd9..423339e 100644 --- a/secant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/secant.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -10,6 +10,15 @@ "version": "0.5.3" } }, + { + "package": "MnemonicSwift", + "repositoryURL": "https://github.com/zcash-hackworks/MnemonicSwift", + "state": { + "branch": null, + "revision": "27711179a75a1172d6f04ceb5d86419cf0cba401", + "version": "2.1.0" + } + }, { "package": "swift-case-paths", "repositoryURL": "https://github.com/pointfreeco/swift-case-paths", @@ -37,6 +46,15 @@ "version": "0.28.1" } }, + { + "package": "swift-crypto", + "repositoryURL": "https://github.com/apple/swift-crypto.git", + "state": { + "branch": null, + "revision": "a8911e0fadc25aef1071d582355bd1037a176060", + "version": "2.0.4" + } + }, { "package": "swift-custom-dump", "repositoryURL": "https://github.com/pointfreeco/swift-custom-dump", diff --git a/secant/MockedDependencies/MnemonicSeedPhraseHandling.swift b/secant/MockedDependencies/MnemonicSeedPhraseHandling.swift deleted file mode 100644 index 0c4e670..0000000 --- a/secant/MockedDependencies/MnemonicSeedPhraseHandling.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// MnemonicSeedPhraseHandling.swift -// wallet -// -// Created by Francisco Gindre on 2/28/20. -// Copyright © 2020 Francisco Gindre. All rights reserved. -// - -import Foundation - -enum MnemonicError: Error { - case invalidSeed - case checksumFailed -} - -protocol MnemonicSeedPhraseHandling { - /** - Random 24 words mnemonic phrase - */ - func randomMnemonic() throws -> String - - /** - Random 24 words mnemonic phrase as array of words - */ - func randomMnemonicWords() throws -> [String] - - /** - Generate deterministic seed from mnemonic phrase - */ - func toSeed(mnemonic: String) throws -> [UInt8] - - /** - Get this mnemonic - */ - func asWords(mnemonic: String) throws -> [String] - - /** - Validates whether the given mnemonic is correct - */ - func isValid(mnemonic: String) throws -} diff --git a/secant/MockedDependencies/Services.swift b/secant/MockedDependencies/Services.swift index dfe6afe..9f2a0c1 100644 --- a/secant/MockedDependencies/Services.swift +++ b/secant/MockedDependencies/Services.swift @@ -9,7 +9,7 @@ import Foundation protocol Services { var networkProvider: ZcashNetworkProvider { get } - var seedHandler: MnemonicSeedPhraseHandling { get } + var seedHandler: MnemonicSeedPhraseProvider { get } var keyStorage: KeyStoring { get } } diff --git a/secant/Stubs/MockServices.swift b/secant/Stubs/MockServices.swift index e9562bc..3cf5922 100644 --- a/secant/Stubs/MockServices.swift +++ b/secant/Stubs/MockServices.swift @@ -7,11 +7,10 @@ // TODO: Move this to different Target when real functionality is developed. import Foundation -// swiftlint:disable line_length class MockServices: Services { var networkProvider: ZcashNetworkProvider = MockNetworkProvider() - var seedHandler: MnemonicSeedPhraseHandling = MockMnemonicPhraseHandling() + var seedHandler: MnemonicSeedPhraseProvider = .mock var keyStorage: KeyStoring = MockKeyStoring() } @@ -22,41 +21,6 @@ class MockNetworkProvider: ZcashNetworkProvider { } } -class MockMnemonicPhraseHandling: MnemonicSeedPhraseHandling { - class TestSeed { - /** - Test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" - */ - let seedString = Data( - base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==" - )!// swiftlint:disable:this force_unwrapping - - func seed() -> [UInt8] { - [UInt8](seedString) - } - } - - func randomMnemonic() throws -> String { - "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" - } - - func randomMnemonicWords() throws -> [String] { - "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" - .components(separatedBy: " ") - } - - func toSeed(mnemonic: String) throws -> [UInt8] { - TestSeed().seed() - } - - func asWords(mnemonic: String) throws -> [String] { - "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" - .components(separatedBy: " ") - } - - func isValid(mnemonic: String) throws {} -} - class KeysPresentStub: KeyStoring { init(returnBlock: @escaping () throws -> Bool) { self.returnBlock = returnBlock diff --git a/secant/Util/MnemonicSeedPhraseProvider.swift b/secant/Util/MnemonicSeedPhraseProvider.swift new file mode 100644 index 0000000..09d72f3 --- /dev/null +++ b/secant/Util/MnemonicSeedPhraseProvider.swift @@ -0,0 +1,83 @@ +// +// MnemonicSeedPhraseProvider.swift +// secant-testnet +// +// Created by Lukáš Korba on 03/09/2022. +// + +import Foundation +import MnemonicSwift + +struct MnemonicSeedPhraseProvider { + /// Random 24 words mnemonic phrase + var randomMnemonic: () throws -> String + /// Random 24 words mnemonic phrase as array of words + var randomMnemonicWords: () throws -> [String] + /// Generate deterministic seed from mnemonic phrase + var toSeed: (String) throws -> [UInt8] + /// Get this mnemonic phrase as array of words + var asWords: (String) throws -> [String] + /// Validates whether the given mnemonic is correct + var isValid: (String) throws -> Void +} + +extension MnemonicSeedPhraseProvider { + static let live = MnemonicSeedPhraseProvider( + randomMnemonic: { + try Mnemonic.generateMnemonic(strength: 256) + }, + randomMnemonicWords: { + try Mnemonic.generateMnemonic(strength: 256).components(separatedBy: " ") + }, + toSeed: { mnemonic in + let data = try Mnemonic.deterministicSeedBytes(from: mnemonic) + + return [UInt8](data) + }, + asWords: { mnemonic in + mnemonic.components(separatedBy: " ") + }, + isValid: { mnemonic in + try Mnemonic.validate(mnemonic: mnemonic) + } + ) + + static let mock = MnemonicSeedPhraseProvider( + randomMnemonic: { + """ + still champion voice habit trend flight \ + survey between bitter process artefact blind \ + carbon truly provide dizzy crush flush \ + breeze blouse charge solid fish spread + """ + }, + randomMnemonicWords: { + let mnemonic = """ + still champion voice habit trend flight \ + survey between bitter process artefact blind \ + carbon truly provide dizzy crush flush \ + breeze blouse charge solid fish spread + """ + + return mnemonic.components(separatedBy: " ") + }, + toSeed: { _ in + let seedString = Data( + base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==" + )!// swiftlint:disable:this force_unwrapping + + return [UInt8](seedString) + }, + asWords: { mnemonic in + let mnemonic = """ + still champion voice habit trend flight \ + survey between bitter process artefact blind \ + carbon truly provide dizzy crush flush \ + breeze blouse charge solid fish spread + """ + + return mnemonic.components(separatedBy: " ") + }, + isValid: { _ in } + ) +}