Repository: essentiaone/HDWallet Branch: develop Commit: c1c5beb470d5 Files: 184 Total size: 715.4 KB Directory structure: gitextract_m1rg5mwu/ ├── .codecov.yml ├── .gitignore ├── .swiftlint.yml ├── .travis.yml ├── Cartfile ├── HDWalletKit/ │ ├── Core/ │ │ ├── BigInt/ │ │ │ ├── BigInt+Extension.swift │ │ │ ├── BigNumber.swift │ │ │ └── SMP.swift │ │ ├── BitcoinScript/ │ │ │ ├── OP_CODE/ │ │ │ │ ├── Arithmetic/ │ │ │ │ │ ├── OP_0NOTEQUAL.swift │ │ │ │ │ ├── OP_1ADD.swift │ │ │ │ │ ├── OP_1SUB.swift │ │ │ │ │ ├── OP_2DIV.swift │ │ │ │ │ ├── OP_2MUL.swift │ │ │ │ │ ├── OP_ABS.swift │ │ │ │ │ ├── OP_ADD.swift │ │ │ │ │ ├── OP_BOOLAND.swift │ │ │ │ │ ├── OP_BOOLOR.swift │ │ │ │ │ ├── OP_DIV.swift │ │ │ │ │ ├── OP_GREATERTHAN.swift │ │ │ │ │ ├── OP_GREATERTHANOREQUAL.swift │ │ │ │ │ ├── OP_LESSTHAN.swift │ │ │ │ │ ├── OP_LESSTHANOREQUAL.swift │ │ │ │ │ ├── OP_LSHIFT.swift │ │ │ │ │ ├── OP_MAX.swift │ │ │ │ │ ├── OP_MIN.swift │ │ │ │ │ ├── OP_MOD.swift │ │ │ │ │ ├── OP_MUL.swift │ │ │ │ │ ├── OP_NEGATE.swift │ │ │ │ │ ├── OP_NOT.swift │ │ │ │ │ ├── OP_NUMEQUAL.swift │ │ │ │ │ ├── OP_NUMEQUALVERIFY.swift │ │ │ │ │ ├── OP_NUMNOTEQUAL.swift │ │ │ │ │ ├── OP_RSHIFT.swift │ │ │ │ │ ├── OP_SUB.swift │ │ │ │ │ └── OP_WITHIN.swift │ │ │ │ ├── Bitwise Logic/ │ │ │ │ │ ├── OP_AND.swift │ │ │ │ │ ├── OP_EQUAL.swift │ │ │ │ │ ├── OP_EQUALVERIFY.swift │ │ │ │ │ ├── OP_INVERT.swift │ │ │ │ │ ├── OP_OR.swift │ │ │ │ │ ├── OP_RESERVED1.swift │ │ │ │ │ ├── OP_RESERVED2.swift │ │ │ │ │ └── OP_XOR.swift │ │ │ │ ├── Crypto/ │ │ │ │ │ ├── OP_CHECKMULTISIG.swift │ │ │ │ │ ├── OP_CHECKMULTISIGVERIFY.swift │ │ │ │ │ ├── OP_CHECKSIG.swift │ │ │ │ │ ├── OP_CHECKSIGVERIFY.swift │ │ │ │ │ ├── OP_CODESEPARATOR.swift │ │ │ │ │ ├── OP_HASH160.swift │ │ │ │ │ ├── OP_HASH256.swift │ │ │ │ │ ├── OP_RIPEMD160.swift │ │ │ │ │ ├── OP_SHA1.swift │ │ │ │ │ └── OP_SHA256.swift │ │ │ │ ├── Flow Control/ │ │ │ │ │ ├── OP_ELSE.swift │ │ │ │ │ ├── OP_ENDIF.swift │ │ │ │ │ ├── OP_IF.swift │ │ │ │ │ ├── OP_NOP.swift │ │ │ │ │ ├── OP_NOTIF.swift │ │ │ │ │ ├── OP_RETURN.swift │ │ │ │ │ ├── OP_VER.swift │ │ │ │ │ ├── OP_VERIF.swift │ │ │ │ │ ├── OP_VERIFY.swift │ │ │ │ │ └── OP_VERNOTIF.swift │ │ │ │ ├── Lock Time/ │ │ │ │ │ ├── OP_CHECKLOCKTIMEVERIFY.swift │ │ │ │ │ └── OP_CHECKSEQUENCEVERIFY.swift │ │ │ │ ├── OP_EXAMPLE.swift │ │ │ │ ├── Pseudo Words/ │ │ │ │ │ ├── OP_INVALIDOPCODE.swift │ │ │ │ │ ├── OP_PUBKEY.swift │ │ │ │ │ └── OP_PUBKEYHASH.swift │ │ │ │ ├── Push Data/ │ │ │ │ │ ├── OP_0.swift │ │ │ │ │ ├── OP_1NEGATE.swift │ │ │ │ │ ├── OP_N.swift │ │ │ │ │ ├── OP_PUSHDATA.swift │ │ │ │ │ └── OP_RESERVED.swift │ │ │ │ ├── Reserved Words/ │ │ │ │ │ └── OP_NOPN.swift │ │ │ │ ├── Splice/ │ │ │ │ │ ├── OP_BIN2NUM.swift │ │ │ │ │ ├── OP_CAT.swift │ │ │ │ │ ├── OP_NUM2BIN.swift │ │ │ │ │ ├── OP_SIZE.swift │ │ │ │ │ └── OP_SPLIT.swift │ │ │ │ └── Stack/ │ │ │ │ ├── OP_2DROP.swift │ │ │ │ ├── OP_2DUP.swift │ │ │ │ ├── OP_2OVER.swift │ │ │ │ ├── OP_2ROT.swift │ │ │ │ ├── OP_2SWAP.swift │ │ │ │ ├── OP_3DUP.swift │ │ │ │ ├── OP_DEPTH.swift │ │ │ │ ├── OP_DROP.swift │ │ │ │ ├── OP_DUP.swift │ │ │ │ ├── OP_FROMALTSTACK.swift │ │ │ │ ├── OP_IFDUP.swift │ │ │ │ ├── OP_NIP.swift │ │ │ │ ├── OP_OVER.swift │ │ │ │ ├── OP_PICK.swift │ │ │ │ ├── OP_ROLL.swift │ │ │ │ ├── OP_ROT.swift │ │ │ │ ├── OP_SWAP.swift │ │ │ │ ├── OP_TOTALSTACK.swift │ │ │ │ └── OP_TUCK.swift │ │ │ ├── OpCodeFactory.swift │ │ │ ├── OpCodeProtocol.swift │ │ │ ├── Opcode.swift │ │ │ ├── Script.swift │ │ │ ├── ScriptChunk.swift │ │ │ ├── ScriptChunkHelper.swift │ │ │ ├── ScriptExecutionContext.swift │ │ │ ├── ScriptFactory.swift │ │ │ └── ScriptMachine.swift │ │ ├── ByteStream.swift │ │ ├── Converter/ │ │ │ └── WeiEthterConverter.swift │ │ ├── Crypto/ │ │ │ ├── Encryption/ │ │ │ │ ├── Crypto.swift │ │ │ │ ├── ECDSA.swift │ │ │ │ ├── EIP155Signer.swift │ │ │ │ ├── EllipticCurveEncrypterSecp256k1.swift │ │ │ │ └── SecpResult.swift │ │ │ └── Hash/ │ │ │ └── RIPEMD160.swift │ │ ├── DataConvertable.swift │ │ ├── DerivationNode.swift │ │ ├── Encodeing/ │ │ │ ├── Base58Encode.swift │ │ │ ├── Bech32.swift │ │ │ ├── EIP55.swift │ │ │ └── RLP.swift │ │ ├── Error/ │ │ │ └── HDWalletKitError.swift │ │ ├── Extensions/ │ │ │ ├── Data+Random.swift │ │ │ ├── Data+Script.swift │ │ │ └── String+Hex.swift │ │ ├── Typealiaces.swift │ │ ├── VarInt.swift │ │ └── VarString.swift │ ├── Keystore/ │ │ ├── KeystoreInterface.swift │ │ ├── KeystoreV3.swift │ │ └── KeystoreV3Json.swift │ ├── Mnemonic/ │ │ ├── Mnemonic.swift │ │ └── WordList.swift │ ├── Models/ │ │ └── Account.swift │ └── Wallet/ │ ├── AccountBased/ │ │ ├── ERC20/ │ │ │ └── ERC20.swift │ │ └── Ethereum/ │ │ └── Model/ │ │ ├── EthereumAddress.swift │ │ └── EthereumRawTransaction.swift │ ├── Coin.swift │ ├── PrivateKey.swift │ ├── PublicKey.swift │ ├── UTXOBased/ │ │ ├── Bitcoin/ │ │ │ ├── BitcoinAddress.swift │ │ │ ├── BitcoinTransactionSignatureSerializer.swift │ │ │ └── Transaction+SignatureHash.swift │ │ ├── BitcoinCash/ │ │ │ ├── BitcoinCashAddress.swift │ │ │ └── BitcoinCashVersionByte.swift │ │ ├── Constants/ │ │ │ ├── SighashType.swift │ │ │ └── UtilsAndLimits.swift │ │ ├── Default/ │ │ │ ├── UtxoSelector.swift │ │ │ ├── UtxoTransactionBuilder.swift │ │ │ └── UtxoTransactionSigner.swift │ │ ├── Model/ │ │ │ ├── TransactionInput.swift │ │ │ ├── UnsignedTransaction.swift │ │ │ └── UnspendTransaction/ │ │ │ ├── TransactionOutPoint.swift │ │ │ ├── TransactionOutput.swift │ │ │ └── UnspendTransaction.swift │ │ ├── Protocols/ │ │ │ ├── UtxoSelectorInterface.swift │ │ │ ├── UtxoTransactionBuilderInterface.swift │ │ │ └── UtxoTransactionSignerInterface.swift │ │ ├── Transaction.swift │ │ ├── UTXOWallet.swift │ │ └── UtxoPrivateKeyType.swift │ └── Wallet.swift ├── HDWalletKit.podspec ├── HDWalletKit.xcodeproj/ │ ├── project.pbxproj │ └── xcshareddata/ │ └── xcschemes/ │ ├── HDWalletKit.xcscheme │ └── HDWalletKit_Tests.xcscheme ├── HDWalletKit_Tests/ │ ├── AddressGenerationTests.swift │ ├── ConverterTests.swift │ ├── CryptoTests.swift │ ├── ERC20Tests.swift │ ├── ImportWalletTests.swift │ ├── Info.plist │ ├── KeystoreTests.swift │ ├── MnemonicTests.swift │ ├── PrivateKeyTests.swift │ ├── RIPEMD160Tests.swift │ ├── Secp256k1Tets.swift │ ├── SignTransactionTests.swift │ └── UTXO/ │ └── UTXOSign.swift ├── LICENSE.md ├── Podfile ├── README.md └── scripts/ └── coverage.rb ================================================ FILE CONTENTS ================================================ ================================================ FILE: .codecov.yml ================================================ ignore: - "**/WordList.swift" ================================================ FILE: .gitignore ================================================ # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated build/ DerivedData/ ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata/ ## Other *.moved-aside *.xccheckout *.xcscmblueprint ## Obj-C/Swift specific *.hmap *.ipa *.dSYM.zip *.dSYM ## Playgrounds timeline.xctimeline playground.xcworkspace # Swift Package Manager # # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. # Packages/ # Package.pins .build/ # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # Pods/ Podfile.lock *.xcworkspace # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/#source-control fastlane/report.xml fastlane/Preview.html fastlane/screenshots fastlane/test_output ================================================ FILE: .swiftlint.yml ================================================ disabled_rules: - trailing_whitespace excluded: - Carthage - Pods ================================================ FILE: .travis.yml ================================================ language: - objective-c osx_image: - xcode10.2.1 before_install: - gem update cocoapods --pre - pod update install: - gem install xcpretty-travis-formatter script: - xcodebuild test -workspace 'HDWalletKit.xcworkspace' -scheme 'HDWalletKit_Tests' -destination 'platform=iOS Simulator,name=iPhone 7,OS=12.1' | xcpretty -f `xcpretty-travis-formatter` after_success: - bash <(curl -s https://copilot.blackducksoftware.com/ci/travis/scripts/upload) - ruby scripts/coverage.rb "$SCHEME" - bash <(curl -s https://codecov.io/bash) -f 'coverage.txt' -y '.codecov.yml' ================================================ FILE: Cartfile ================================================ github "Boilertalk/secp256k1.swift" github "krzyzanowskim/CryptoSwift" ================================================ FILE: HDWalletKit/Core/BigInt/BigInt+Extension.swift ================================================ // // BigInt+Extension.swift // WalletKit // // Created by yuzushioh on 2018/01/24. // Copyright © 2018 yuzushioh. All rights reserved. // import Foundation extension BInt { internal init?(str: String, radix: Int) { self.init(0) let bint16 = BInt(16) var exp = BInt(1) str.reversed().forEach { guard let int = Int(String($0), radix: radix) else { return } let value = BInt(int) self += (value * exp) exp *= bint16 } } } extension BInt: Codable { private enum CodingKeys: String, CodingKey { case bigInt } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let string = try container.decode(String.self, forKey: .bigInt) self = Wei(number: string, withBase: 10)! } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(asString(withBase: 10), forKey: .bigInt) } } extension BInt { var data: Data { let count = limbs.count var data = Data(count: count * 8) data.withUnsafeMutableBytes { (pointer) -> Void in guard var p = pointer.bindMemory(to: UInt8.self).baseAddress else { return } for i in (0..> UInt64(j * 8)) & 0xff) p += 1 } } } return data } init?(hex: String) { self.init(number: hex.lowercased(), withBase: 16) } init(data: Data) { let n = data.count guard n > 0 else { self.init(0) return } let m = (n + 7) / 8 var limbs = Limbs(repeating: 0, count: m) data.withUnsafeBytes { (ptr) -> Void in guard var p = ptr.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return } let r = n % 8 let k = r == 0 ? 8 : r for j in (0.. 1 else { return } for i in (0..<(m - 1)).reversed() { for j in (0..<8).reversed() { limbs[i] += UInt64(p.pointee) << UInt64(j * 8) p += 1 } } } self.init(limbs: limbs) } } ================================================ FILE: HDWalletKit/Core/BigInt/BigNumber.swift ================================================ // // BigNumber.swift // HDWalletKit // // Created by Pavlo Boiko on 1/6/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public struct BigNumber { public var int32: Int32 public var data: Data public static let zero: BigNumber = BigNumber() public static let one: BigNumber = BigNumber(1) public static let negativeOne: BigNumber = BigNumber(1) public init() { self.init(0) } public init(_ int32: Int32) { self.int32 = int32 self.data = int32.toBigNum() } public init(int32: Int32) { self.int32 = int32 self.data = int32.toBigNum() } public init(_ data: Data) { self.data = data self.int32 = data.toInt32() } } extension BigNumber: Comparable { public static func == (lhs: BigNumber, rhs: BigNumber) -> Bool { return lhs.int32 == rhs.int32 } public static func < (lhs: BigNumber, rhs: BigNumber) -> Bool { return lhs.int32 < rhs.int32 } } private extension Int32 { func toBigNum() -> Data { let isNegative: Bool = self < 0 var value: UInt32 = isNegative ? UInt32(-self) : UInt32(self) var data = Data(bytes: &value, count: MemoryLayout.size(ofValue: value)) while data.last == 0 { data.removeLast() } var bytes: [UInt8] = [] for d in data.reversed() { if bytes.isEmpty && d >= 0x80 { bytes.append(0) } bytes.append(d) } if isNegative { let first = bytes.removeFirst() bytes.insert(first + 0x80, at: 0) } let bignum = Data(bytes.reversed()) return bignum } } private extension Data { func toInt32() -> Int32 { guard !self.isEmpty else { return 0 } var data = self var bytes: [UInt8] = [] var last = data.removeLast() let isNegative: Bool = last >= 0x80 while !data.isEmpty { bytes.append(data.removeFirst()) } if isNegative { last -= 0x80 } bytes.append(last) let value: Int32 = Data(bytes).to(type: Int32.self) return isNegative ? -value: value } } ================================================ FILE: HDWalletKit/Core/BigInt/SMP.swift ================================================ // // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||||||||||| SMP Core.swift |||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— // Created by Marcel Kröker on 30.09.16. // Copyright (c) 2016 Blubyte. All rights reserved. // // // // ——————————————————————————————————————————— v1.0 ——————————————————————————————————————————— // - Initial Release. // // ——————————————————————————————————————————— v1.1 ——————————————————————————————————————————— // - Improved String conversion, now about 45x faster, uses base 10^9 instead // of base 10. // - bytes renamed to limbs. // - Uses typealias for limbs and digits. // // ——————————————————————————————————————————— v1.2 ——————————————————————————————————————————— // - Improved String conversion, now about 10x faster, switched from base 10^9 // to 10^18 (biggest possible decimal base). // - Implemented karatsuba multiplication algorithm, about 5x faster than the // previous algorithm. // - Addition is 1.3x faster. // - Addtiton and subtraction omit trailing zeros, algorithms need less // operations now. // - Implemented exponentiation by squaring. // - New storage (BStorage) for often used results. // - Uses uint_fast64_t instead of UInt64 for Limbs and Digits. // // ——————————————————————————————————————————— v1.3 ——————————————————————————————————————————— // - Huge Perfomance increase by skipping padding zeros and new multiplication // algotithms. // - Printing is now about 10x faster, now on par with GMP. // - Some operations now use multiple cores. // // ——————————————————————————————————————————— v1.4 ——————————————————————————————————————————— // - Reduced copying by using more pointers. // - Multiplication is about 50% faster. // - String to BInt conversion is 2x faster. // - BInt to String also performs 50% better. // // ——————————————————————————————————————————— v1.5 ——————————————————————————————————————————— // - Updated for full Swift 3 compatibility. // - Various optimizations: // - Multiplication is about 2x faster. // - BInt to String conversion is more than 3x faster. // - String to BInt conversion is more than 2x faster. // // ——————————————————————————————————————————— v1.6 ——————————————————————————————————————————— // - Code refactored into modules. // - Renamed the project to SMP (Swift Multiple Precision). // - Added arbitrary base conversion. // // ——————————————————————————————————————————— v2.0 ——————————————————————————————————————————— // - Updated for full Swift 4 compatibility. // - Big refactor, countless optimizations for even better performance. // - BInt conforms to SignedNumeric and BinaryInteger, this makes it very easy to write // generic code. // - BDouble also conforms to SignedNumeric and has new functionalities. // // // // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||||||||||| Evolution |||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— // // // // Planned features of BInt v3.0: // - Implement some basic cryptography functions. // - General code cleanup, better documentation. // - More extensive tests. // - Please contact me if you have any suggestions for new features! // // // // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||||||||||| Basic Project syntax conventions |||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— // // Indentation: Tabs // // Align: Spaces // // Style: allman // func foo(...) // { // ... // } // // Single line if-statement: // if condition { code } // // Maximum line length: 96 characters // // ———————————————————————————————————————————————————————————————————————————————————————————— // MARK: - Imports // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||| Imports ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— import Foundation // MARK: - Typealiases // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||| Typealiases ||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— // Limbs are basically single Digits in base 2^64. Each slot in an Limbs array stores one // Digit of the number. The least significant digit is stored at index 0, the most significant // digit is stored at the last index. public typealias Limbs = [UInt64] public typealias Limb = UInt64 // A digit is a number in base 10^18. This is the biggest possible base that // fits into an unsigned 64 bit number while maintaining the propery that the square root of // the base is a whole number and a power of ten . Digits are required for printing BInt // numbers. Limbs are converted into Digits first, and then printed. public typealias Digits = [UInt64] public typealias Digit = UInt64 // MARK: - Imports // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||| Operators ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— precedencegroup ExponentiationPrecedence { associativity: left higherThan: MultiplicationPrecedence lowerThan: BitwiseShiftPrecedence } // Exponentiation operator infix operator ** : ExponentiationPrecedence // MARK: - BInt // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||| BInt |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— /// BInt is an arbitrary precision integer value type. It stores a number in base 2^64 notation /// as an array. Each element of the array is called a limb, which is of type UInt64, the whole /// array is called limbs and has the type [UInt64]. A boolean sign variable determines if the /// number is positive or negative. If sign == true, then the number is smaller than 0, /// otherwise it is greater or equal to 0. It stores the 64 bit digits in little endian, that /// is, the least significant digit is stored in the array index 0: /// /// limbs == [] := undefined, should throw an error /// limbs == [0], sign == false := 0, defined as positive /// limbs == [0], sign == true := undefined, should throw an error /// limbs == [n] := n if sign == false, otherwise -n, given 0 <= n < 2^64 /// /// limbs == [l0, l1, l2, ..., ln] := /// (l0 * 2^(0*64)) + /// (11 * 2^(1*64)) + /// (12 * 2^(2*64)) + /// ... + /// (ln * 2^(n*64)) public struct BInt: SignedNumeric, // Implies Numeric, Equatable, ExpressibleByIntegerLiteral BinaryInteger, // Implies Hashable, CustomStringConvertible, Strideable, Comparable ExpressibleByFloatLiteral { // // // MARK: - Internal data // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Internal data ||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // internal var sign = false internal var limbs = Limbs() // Required by protocol Numeric public typealias Magnitude = UInt64 // Required by protocol Numeric public var magnitude: UInt64 { return self.limbs[0] } public typealias Words = [UInt] /// A collection containing the words of this value’s binary representation, in order from /// the least significant to most significant. public var words: BInt.Words { return self.limbs.map { UInt($0) } } /// Returns the size of the BInt in bits. public var size: Int { return 1 + (self.limbs.count * MemoryLayout.size * 8) } // // // MARK: - Initializers // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Initializers |||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // /// Root initializer for all other initializers. Because no sign is provided, the new /// instance is positive by definition. internal init(limbs: Limbs) { precondition(limbs != [], "BInt can't be initialized with limbs == []") self.limbs = limbs } /// Create an instance initialized with a sign and a limbs array. internal init(sign: Bool, limbs: Limbs) { self.init(limbs: limbs) self.sign = sign } /// Create an instance initialized with the value 0. init() { self.init(limbs: [0]) } /// Create an instance initialized to an integer value. public init(_ z: Int) { // Since abs(Int.min) > Int.max, it is necessary to handle // z == Int.min as a special case. if z == Int.min { self.init(sign: true, limbs: [Limb(Int.max) + 1]) return } else { self.init(sign: z < 0, limbs: [Limb(abs(z))]) } } /// Create an instance initialized to an unsigned integer value. public init(_ n: UInt) { self.init(limbs: [Limb(n)]) } /// Create an instance initialized to a string value. public init?(_ str: String) { var str = str var sign = false var base: Limbs = [1] var limbs: Limbs = [0] limbs.reserveCapacity(Int(Double(str.count) / log10(pow(2.0, 64.0)))) if str.hasPrefix("-") { str.remove(at: str.startIndex) sign = str != "0" } for chunk in String(str.reversed()).split(19).map({ String($0.reversed()) }) { if let num = Limb(String(chunk)) { limbs.addProductOf(multiplier: base, multiplicand: num) base = base.multiplyingBy([10_000_000_000_000_000_000]) } else { return nil } } self.init(sign: sign, limbs: limbs) } /// Create an instance initialized to a string with the value of mathematical numerical system of the specified radix (base). /// So for example, to get the value of hexadecimal string radix value must be set to 16. public init?(_ nStr: String, radix: Int) { if radix == 10 { // regular string init is faster // see metrics self.init(nStr) return } var useString = nStr if radix == 16 { if useString.hasPrefix("0x") { useString = String(nStr.dropFirst(2)) } } if radix == 8 { if useString.hasPrefix("0o") { useString = String(nStr.dropFirst(2)) } } if radix == 2 { if useString.hasPrefix("0b") { useString = String(nStr.dropFirst(2)) } } let bint16 = BInt(radix) var total = BInt(0) var exp = BInt(1) for c in useString.reversed() { let int = Int(String(c), radix: radix) if int != nil { let value = BInt(int!) total = total + (value * exp) exp = exp * bint16 } else { return nil } } self.init(String(describing: total)) } // Requierd by protocol ExpressibleByFloatLiteral. public init(floatLiteral value: Double) { self.init(sign: value < 0.0, limbs: [Limb(value)]) } // Required by protocol ExpressibleByIntegerLiteral. public init(integerLiteral value: Int) { self.init(value) } // Required by protocol Numeric public init?(exactly source: T) where T: BinaryInteger { self.init(Int(source)) } /// Creates an integer from the given floating-point value, rounding toward zero. public init(_ source: T) where T: BinaryFloatingPoint { self.init(Int(source)) } /// Creates a new instance from the given integer. public init(_ source: T) where T: BinaryInteger { self.init(Int(source)) } /// Creates a new instance with the representable value that’s closest to the given integer. public init(clamping source: T) where T: BinaryInteger { self.init(Int(source)) } /// Creates an integer from the given floating-point value, if it can be represented /// exactly. public init?(exactly source: T) where T: BinaryFloatingPoint { self.init(source) } /// Creates a new instance from the bit pattern of the given instance by sign-extending or /// truncating to fit this type. public init(truncatingIfNeeded source: T) where T: BinaryInteger { self.init(source) } // // // MARK: - CustomStringConvertible conformance // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| CustomStringConvertible conformance ||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // public var description: String { return (self.sign ? "-" : "").appending(self.limbs.decimalRepresentation) } public init?(number: String, withBase base: Int) { self.init(number.convertingBase(from: base, toBase: 10)) } public func asString(withBase base: Int) -> String { let str = self.limbs.decimalRepresentation let newStr = str.convertingBase(from: 10, toBase: base) if self.sign { return "-".appending(newStr) } return newStr } // // // MARK: - Struct functions // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Struct functions |||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // /// Returns BInt value as an integer, if possible. func toInt() -> Int? { // Conversion only works when self has only one limb thats smaller or // equal to abs(Int.min). if self.limbs.count != 1 { return nil } let number = self.limbs[0] // Self is within the range of Int if number <= Limb(Int.max) { return self.sign ? -Int(number) : Int(number) } // Special case: self == Int.min if number == (Limb(Int.max) + 1) && self.sign { return Int.min } return nil } var rawValue: (sign: Bool, limbs: [UInt64]) { return (self.sign, self.limbs) } /// A Boolean value indicating whether this type is a signed integer type. public static var isSigned: Bool { return true } /// Returns -1 if this value is negative and 1 if it’s positive; otherwise, 0. public func signum() -> BInt { if self.isZero() { return BInt(0) } else if self.isPositive() { return BInt(1) } else { return BInt(-1) } } func isPositive() -> Bool { return !self.sign } func isNegative() -> Bool { return self.sign } func isZero() -> Bool { return self.limbs[0] == 0 && self.limbs.count == 1 } func isNotZero() -> Bool { return self.limbs[0] != 0 || self.limbs.count > 1 } func isOdd() -> Bool { return self.limbs[0] & 1 == 1 } func isEven() -> Bool { return self.limbs[0] & 1 == 0 } /// The number of bits in the current binary representation of this value. public var bitWidth: Int { return self.limbs.bitWidth } /// The number of trailing zeros in this value’s binary representation. public var trailingZeroBitCount: Int { var i = 0 while true { if self.limbs.getBit(at: i) { return i } i += 1 } } /// Serialization public func serialize() -> Data { let byteCount = (bitWidth + 7) / 8 guard byteCount > 0 else { return Data()} var data = Data(count: byteCount) data.withUnsafeMutableBytes { (pointer) -> Void in let p = pointer.bindMemory(to: UInt8.self) var i = byteCount - 1 for var word in words { for _ in 0 ..< UInt.bitWidth / 8 { p[i] = UInt8(word & 0xFF) word >>= 8 if i == 0 { assert(word == 0) break } i -= 1 } } } return data } // // // MARK: - BInt Shifts // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Shifts ||||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // public static func <<(lhs: BInt, rhs: T) -> BInt { if rhs < 0 { return lhs >> rhs } let limbs = lhs.limbs.shiftingUp(Int(rhs)) let sign = lhs.isNegative() && !limbs.equalTo(0) return BInt(sign: sign, limbs: limbs) } public static func <<=(lhs: inout BInt, rhs: T) { lhs.limbs.shiftUp(Int(rhs)) } public static func >>(lhs: BInt, rhs: T) -> BInt { if rhs < 0 { return lhs << rhs } return BInt(sign: lhs.sign, limbs: lhs.limbs.shiftingDown(Int(rhs))) } public static func >>=(lhs: inout BInt, rhs: T) { lhs.limbs.shiftDown(Int(rhs)) } // // // MARK: - BInt Bitwise AND // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt BInt Bitwise AND ||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // /// Returns the result of performing a bitwise AND operation on the two given values. public static func &(lhs: BInt, rhs: BInt) -> BInt { var res: Limbs = [0] for i in 0..<(64 * Swift.max(lhs.limbs.count, rhs.limbs.count)) { let newBit = lhs.limbs.getBit(at: i) && lhs.limbs.getBit(at: i) res.setBit(at: i, to: newBit) } return BInt(sign: lhs.sign && rhs.sign, limbs: res) } // static func &(lhs: Int, rhs: BInt) -> BInt // static func &(lhs: BInt, rhs: Int) -> BInt /// Stores the result of performing a bitwise AND operation on the two given values in the /// left-hand-side variable. public static func &=(lhs: inout BInt, rhs: BInt) { let res = lhs & rhs lhs = res } // static func &=(inout lhs: Int, rhs: BInt) // static func &=(inout lhs: BInt, rhs: Int) // // // MARK: - BInt Bitwise OR // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Bitwise OR ||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // public static func |(lhs: BInt, rhs: BInt) -> BInt { var res: Limbs = [0] for i in 0..<(64 * Swift.max(lhs.limbs.count, rhs.limbs.count)) { let newBit = lhs.limbs.getBit(at: i) || lhs.limbs.getBit(at: i) res.setBit(at: i, to: newBit) } return BInt(sign: lhs.sign || rhs.sign, limbs: res) } // static func |(lhs: Int, rhs: BInt) -> BInt // static func |(lhs: BInt, rhs: Int) -> BInt // public static func |=(lhs: inout BInt, rhs: BInt) { let res = lhs | rhs lhs = res } // static func |=(inout lhs: Int, rhs: BInt) // static func |=(inout lhs: BInt, rhs: Int) // // // MARK: - BInt Bitwise OR // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Bitwise XOR |||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // public static func ^(lhs: BInt, rhs: BInt) -> BInt { var res: Limbs = [0] for i in 0..<(64 * Swift.max(lhs.limbs.count, rhs.limbs.count)) { let newBit = lhs.limbs.getBit(at: i) != lhs.limbs.getBit(at: i) res.setBit(at: i, to: newBit) } return BInt(sign: lhs.sign != rhs.sign, limbs: res) } public static func ^=(lhs: inout BInt, rhs: BInt) { let res = lhs | rhs lhs = res } // // // MARK: - BInt Bitwise NOT // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Bitwise NOT |||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // public prefix static func ~(x: BInt) -> BInt { var res = x.limbs for i in 0..<(res.bitWidth) { res.setBit(at: i, to: !res.getBit(at: i)) } while res.last! == 0 && res.count > 1 { res.removeLast() } return BInt(sign: !x.sign, limbs: res) } // // // MARK: - BInt Addition // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Addition ||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // public prefix static func +(x: BInt) -> BInt { return x } // Required by protocol Numeric public static func +=(lhs: inout BInt, rhs: BInt) { if lhs.sign == rhs.sign { lhs.limbs.addLimbs(rhs.limbs) return } let rhsIsMin = rhs.limbs.lessThan(lhs.limbs) lhs.limbs.difference(rhs.limbs) lhs.sign = (rhs.sign && !rhsIsMin) || (lhs.sign && rhsIsMin) // DNF minimization if lhs.isZero() { lhs.sign = false } } // Required by protocol Numeric public static func +(lhs: BInt, rhs: BInt) -> BInt { var lhs = lhs lhs += rhs return lhs } static func +(lhs: Int, rhs: BInt) -> BInt { return BInt(lhs) + rhs } static func +(lhs: BInt, rhs: Int) -> BInt { return lhs + BInt(rhs) } static func +=(lhs: inout Int, rhs: BInt) { lhs += (BInt(lhs) + rhs).toInt()! } static func +=(lhs: inout BInt, rhs: Int) { lhs += BInt(rhs) } // // // MARK: - BInt Negation // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Negation ||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // // Required by protocol SignedNumeric public mutating func negate() { if self.isNotZero() { self.sign = !self.sign } } // Required by protocol SignedNumeric public static prefix func -(n: BInt) -> BInt { var n = n n.negate() return n } // // // MARK: - BInt Subtraction // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Subtraction |||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // // Required by protocol Numeric public static func -(lhs: BInt, rhs: BInt) -> BInt { return lhs + -rhs } static func -(lhs: Int, rhs: BInt) -> BInt { return BInt(lhs) - rhs } static func -(lhs: BInt, rhs: Int) -> BInt { return lhs - BInt(rhs) } // Required by protocol Numeric public static func -=(lhs: inout BInt, rhs: BInt) { lhs += -rhs } static func -=(lhs: inout Int, rhs: BInt) { lhs = (BInt(lhs) - rhs).toInt()! } static func -=(lhs: inout BInt, rhs: Int) { lhs -= BInt(rhs) } // // // MARK: - BInt Multiplication // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Multiplication ||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // // Required by protocol Numeric public static func *(lhs: BInt, rhs: BInt) -> BInt { let sign = !(lhs.sign == rhs.sign || lhs.isZero() || rhs.isZero()) return BInt(sign: sign, limbs: lhs.limbs.multiplyingBy(rhs.limbs)) } static func *(lhs: Int, rhs: BInt) -> BInt { return BInt(lhs) * rhs } static func *(lhs: BInt, rhs: Int) -> BInt { return lhs * BInt(rhs) } // Required by protocol SignedNumeric public static func *=(lhs: inout BInt, rhs: BInt) { lhs = lhs * rhs } static func *=(lhs: inout Int, rhs: BInt) { lhs = (BInt(lhs) * rhs).toInt()! } static func *=(lhs: inout BInt, rhs: Int) { lhs = lhs * BInt(rhs) } // // // MARK: - BInt Exponentiation // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Exponentiation ||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // static func **(lhs: BInt, rhs: Int) -> BInt { precondition(rhs >= 0, "BInts can't be exponentiated with exponents < 0") return BInt(sign: lhs.sign && (rhs % 2 != 0), limbs: lhs.limbs.exponentiating(rhs)) } func factorial() -> BInt { precondition(!self.sign, "Can't calculate the factorial of an negative number") return BInt(limbs: Limbs.recursiveMul(0, Limb(self.toInt()!))) } // // // MARK: - BInt Division // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Division ||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // /// Returns the quotient and remainder of this value divided by the given value. public func quotientAndRemainder(dividingBy rhs: BInt) -> (quotient: BInt, remainder: BInt) { let limbRes = self.limbs.divMod(rhs.limbs) return (BInt(limbs: limbRes.quotient), BInt(limbs: limbRes.remainder)) } public static func /(lhs: BInt, rhs: BInt) -> BInt { let limbs = lhs.limbs.divMod(rhs.limbs).quotient let sign = (lhs.sign != rhs.sign) && !limbs.equalTo(0) return BInt(sign: sign, limbs: limbs) } static func /(lhs: Int, rhs: BInt) -> BInt { return BInt(lhs) / rhs } static func /(lhs: BInt, rhs: Int) -> BInt { return lhs / BInt(rhs) } public static func /=(lhs: inout BInt, rhs: BInt) { lhs = lhs / rhs } static func /=(lhs: inout BInt, rhs: Int) { lhs = lhs / BInt(rhs) } // // // MARK: - BInt Modulus // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Modulus |||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // public static func %(lhs: BInt, rhs: BInt) -> BInt { let limbs = lhs.limbs.divMod(rhs.limbs).remainder let sign = lhs.sign && !limbs.equalTo(0) return BInt(sign: sign, limbs: limbs) } static func %(lhs: Int, rhs: BInt) -> BInt { return BInt(lhs) % rhs } static func %(lhs: BInt, rhs: Int) -> BInt { return lhs % BInt(rhs) } public static func %=(lhs: inout BInt, rhs: BInt) { lhs = lhs % rhs } static func %=(lhs: inout BInt, rhs: Int) { lhs = lhs % BInt(rhs) } // // // MARK: - BInt Comparing // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| BInt Comparing |||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // // Required by protocol Equatable public static func ==(lhs: BInt, rhs: BInt) -> Bool { if lhs.sign != rhs.sign { return false } return lhs.limbs == rhs.limbs } static func ==(lhs: BInt, rhs: T) -> Bool { if lhs.limbs.count != 1 { return false } return lhs.limbs[0] == rhs } static func ==(lhs: T, rhs: BInt) -> Bool { return rhs == lhs } static func !=(lhs: BInt, rhs: BInt) -> Bool { if lhs.sign != rhs.sign { return true } return lhs.limbs != rhs.limbs } static func !=(lhs: BInt, rhs: T) -> Bool { if lhs.limbs.count != 1 { return true } return lhs.limbs[0] != rhs } static func !=(lhs: T, rhs: BInt) -> Bool { return rhs != lhs } // Required by protocol Comparable public static func <(lhs: BInt, rhs: BInt) -> Bool { if lhs.sign != rhs.sign { return lhs.sign } if lhs.sign { return rhs.limbs.lessThan(lhs.limbs) } return lhs.limbs.lessThan(rhs.limbs) } static func <(lhs: BInt, rhs: T) -> Bool { if lhs.sign != (rhs < 0) { return lhs.sign } if lhs.sign { if lhs.limbs.count != 1 { return true } return rhs < lhs.limbs[0] } else { if lhs.limbs.count != 1 { return false } return lhs.limbs[0] < rhs } } static func <(lhs: Int, rhs: BInt) -> Bool { return BInt(lhs) < rhs } static func <(lhs: BInt, rhs: Int) -> Bool { return lhs < BInt(rhs) } // Required by protocol Comparable public static func >(lhs: BInt, rhs: BInt) -> Bool { return rhs < lhs } static func >(lhs: Int, rhs: BInt) -> Bool { return BInt(lhs) > rhs } static func >(lhs: BInt, rhs: Int) -> Bool { return lhs > BInt(rhs) } // Required by protocol Comparable public static func <=(lhs: BInt, rhs: BInt) -> Bool { return !(rhs < lhs) } static func <=(lhs: Int, rhs: BInt) -> Bool { return !(rhs < BInt(lhs)) } static func <=(lhs: BInt, rhs: Int) -> Bool { return !(BInt(rhs) < lhs) } // Required by protocol Comparable public static func >=(lhs: BInt, rhs: BInt) -> Bool { return !(lhs < rhs) } static func >=(lhs: Int, rhs: BInt) -> Bool { return !(BInt(lhs) < rhs) } static func >=(lhs: BInt, rhs: Int) -> Bool { return !(lhs < BInt(rhs)) } } // // // MARK: - String operations // ———————————————————————————————————————————————————————————————————————————————————————————— // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||| String operations ||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————————— // // // fileprivate extension String { // Splits the string into equally sized parts (exept for the last one). func split(_ count: Int) -> [String] { return stride(from: 0, to: self.count, by: count).map { i -> String in let start = index(startIndex, offsetBy: i) let end = index(start, offsetBy: count, limitedBy: endIndex) ?? endIndex return String(self[start.. String { let chars: [Character] = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ] var res = "" var number = self if number.hasPrefix("-") { res = "-" number.removeFirst() } var sum = BInt(0) var multiplier = BInt(1) for char in number.reversed() { if let digit = chars.firstIndex(of: char) { precondition(digit < from) sum += digit * multiplier multiplier *= from } else { fatalError() } } repeat { res.insert(chars[(sum % toBase).toInt()!], at: res.startIndex) sum /= BInt(toBase) } while sum != 0 return res } } private let DigitBase: Digit = 1_000_000_000_000_000_000 private let DigitHalfBase: Digit = 1_000_000_000 private let DigitZeros = 18 fileprivate extension Array where Element == Limb { var decimalRepresentation: String { // First, convert limbs to digits var digits: Digits = [0] var power: Digits = [1] for limb in self { let digit = (limb >= DigitBase) ? [limb % DigitBase, limb / DigitBase] : [limb] digits.addProductOfDigits(digit, power) var nextPower: Digits = [0] nextPower.addProductOfDigits(power, [446_744_073_709_551_616, 18]) power = nextPower } // Then, convert digits to string var res = String(digits.last!) if digits.count == 1 { return res } for i in (0..<(digits.count - 1)).reversed() { let str = String(digits[i]) let leadingZeros = String(repeating: "0", count: DigitZeros - str.count) res.append(leadingZeros.appending(str)) } return res } } fileprivate extension Digit { mutating func addReportingOverflowDigit(_ addend: Digit) -> Bool { self = self &+ addend if self >= DigitBase { self -= DigitBase; return true } return false } func multipliedFullWidthDigit(by multiplicand: Digit) -> (Digit, Digit) { let (lLo, lHi) = (self % DigitHalfBase, self / DigitHalfBase) let (rLo, rHi) = (multiplicand % DigitHalfBase, multiplicand / DigitHalfBase) let K = (lHi * rLo) + (rHi * lLo) var resLo = (lLo * rLo) + ((K % DigitHalfBase) * DigitHalfBase) var resHi = (lHi * rHi) + (K / DigitHalfBase) if resLo >= DigitBase { resLo -= DigitBase resHi += 1 } return (resLo, resHi) } } fileprivate extension Array where Element == Digit { mutating func addOneDigit( _ addend: Limb, padding paddingZeros: Int ) { let sc = self.count if paddingZeros > sc { self += Digits(repeating: 0, count: paddingZeros &- sc) } if paddingZeros >= sc { self.append(addend); return } // Now, i < sc var i = paddingZeros let ovfl = self[i].addReportingOverflowDigit(addend) while ovfl { i += 1 if i == sc { self.append(1); return } self[i] += 1 if self[i] != DigitBase { return } self[i] = 0 } } mutating func addTwoDigit( _ addendLow: Limb, _ addendHigh: Limb, padding paddingZeros: Int) { let sc = self.count if paddingZeros > sc { self += Digits(repeating: 0, count: paddingZeros &- sc) } if paddingZeros >= sc { self += [addendLow, addendHigh]; return } // Now, i < sc var i = paddingZeros var newDigit: Digit let ovfl1 = self[i].addReportingOverflowDigit(addendLow) i += 1 if i == sc { newDigit = (addendHigh &+ (ovfl1 ? 1 : 0)) % DigitBase self.append(newDigit) if newDigit == 0 { self.append(1) } return } // Still, i < sc var ovfl2 = self[i].addReportingOverflowDigit(addendHigh) if ovfl1 { self[i] += 1 if self[i] == DigitBase { self[i] = 0; ovfl2 = true } } while ovfl2 { i += 1 if i == sc { self.append(1); return } self[i] += 1 if self[i] != DigitBase { return } self[i] = 0 } } mutating func addProductOfDigits(_ multiplier: Digits, _ multiplicand: Digits) { let (mpc, mcc) = (multiplier.count, multiplicand.count) self.reserveCapacity(mpc &+ mcc) var l, r, resLo, resHi: Digit for i in 0..>= 1 lastBits += 1 } return ((self.count - 1) * 64) + lastBits } /// Get bit i of limbs. func getBit(at i: Int) -> Bool { let limbIndex = Int(Limb(i) >> 6) if limbIndex >= self.count { return false } let bitIndex = Limb(i) & 0b111_111 return (self[limbIndex] & (1 << bitIndex)) != 0 } /// Set bit i of limbs to b. b must be 0 for false, and everything else for true. mutating func setBit( at i: Int, to bit: Bool ) { let limbIndex = Int(Limb(i) >> 6) if limbIndex >= self.count && !bit { return } let bitIndex = Limb(i) & 0b111_111 while limbIndex >= self.count { self.append(0) } if bit { self[limbIndex] |= (1 << bitIndex) } else { self[limbIndex] &= ~(1 << bitIndex) } } // // // MARK: - Limbs Shifting // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Limbs Shifting |||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // mutating func shiftUp(_ shift: Int) { // No shifting is required in this case if shift == 0 || self.equalTo(0) { return } let limbShifts = shift >> 6 let bitShifts = Limb(shift) & 0x3f if bitShifts != 0 { var previousCarry = Limb(0) var carry = Limb(0) var ele = Limb(0) // use variable to minimize array accesses for i in 0..> (64 - bitShifts) ele <<= bitShifts ele |= previousCarry // carry from last step previousCarry = carry self[i] = ele } if previousCarry != 0 { self.append(previousCarry) } } if limbShifts != 0 { self.insert(contentsOf: Limbs(repeating: 0, count: limbShifts), at: 0) } } func shiftingUp(_ shift: Int) -> Limbs { var res = self res.shiftUp(shift) return res } mutating func shiftDown(_ shift: Int) { if shift == 0 || self.equalTo(0) { return } let limbShifts = shift >> 6 let bitShifts = Limb(shift) & 0x3f if limbShifts >= self.count { self = [0] return } self.removeSubrange(0..= 0 { ele = self[i] carry = ele << (64 - bitShifts) ele >>= bitShifts ele |= previousCarry previousCarry = carry self[i] = ele i -= 1 } } if self.last! == 0 && self.count != 1 { self.removeLast() } } func shiftingDown(_ shift: Int) -> Limbs { var res = self res.shiftDown(shift) return res } // // // MARK: - Limbs Addition // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Limbs Addition |||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // mutating func addLimbs(_ addend: Limbs) { let (sc, ac) = (self.count, addend.count) var (newLimb, ovfl) = (Limb(0), false) let minCount = Swift.min(sc, ac) var i = 0 while i < minCount { if ovfl { (newLimb, ovfl) = self[i].addingReportingOverflow(addend[i]) newLimb = newLimb &+ 1 ovfl = ovfl || newLimb == 0 } else { (newLimb, ovfl) = self[i].addingReportingOverflow(addend[i]) } self[i] = newLimb i += 1 } while ovfl { if i < sc { if i < ac { (newLimb, ovfl) = self[i].addingReportingOverflow(addend[i]) newLimb = newLimb &+ 1 ovfl = ovfl || newLimb == 0 } else { (newLimb, ovfl) = self[i].addingReportingOverflow(1) } self[i] = newLimb } else { if i < ac { (newLimb, ovfl) = addend[i].addingReportingOverflow(1) self.append(newLimb) } else { self.append(1) return } } i += 1 } if self.count < ac { self.append(contentsOf: addend.suffix(from: i)) } } /// Adding Limbs and returning result func adding(_ addend: Limbs) -> Limbs { var res = self res.addLimbs(addend) return res } // CURRENTLY NOT USED: /// Add the addend to Limbs, while using a padding at the lower end. /// Every zero is a Limb, that means one padding zero equals 64 padding bits mutating func addLimbs( _ addend: Limbs, padding paddingZeros: Int ) { let sc = self.count if paddingZeros > sc { self += Digits(repeating: 0, count: paddingZeros &- sc) } if paddingZeros >= sc { self += addend; return } // Now, i < sc let ac = addend.count &+ paddingZeros var (newLimb, ovfl) = (Limb(0), false) let minCount = Swift.min(sc, ac) var i = paddingZeros while i < minCount { if ovfl { (newLimb, ovfl) = self[i].addingReportingOverflow(addend[i &- paddingZeros]) newLimb = newLimb &+ 1 self[i] = newLimb ovfl = ovfl || newLimb == 0 } else { (self[i], ovfl) = self[i].addingReportingOverflow(addend[i &- paddingZeros]) } i += 1 } while ovfl { if i < sc { let adding = i < ac ? addend[i &- paddingZeros] &+ 1 : 1 (self[i], ovfl) = self[i].addingReportingOverflow(adding) ovfl = ovfl || adding == 0 } else { if i < ac { (newLimb, ovfl) = addend[i &- paddingZeros].addingReportingOverflow(1) self.append(newLimb) } else { self.append(1) return } } i += 1 } if self.count < ac { self.append(contentsOf: addend.suffix(from: i &- paddingZeros)) } } mutating func addOneLimb( _ addend: Limb, padding paddingZeros: Int ) { let sc = self.count if paddingZeros > sc { self += Digits(repeating: 0, count: paddingZeros &- sc) } if paddingZeros >= sc { self.append(addend); return } // Now, i < lhc var i = paddingZeros var ovfl: Bool (self[i], ovfl) = self[i].addingReportingOverflow(addend) while ovfl { i += 1 if i == sc { self.append(1); return } (self[i], ovfl) = self[i].addingReportingOverflow(1) } } /// Basically self.addOneLimb([addendLow, addendHigh], padding: paddingZeros), but faster mutating func addTwoLimb( _ addendLow: Limb, _ addendHigh: Limb, padding paddingZeros: Int) { let sc = self.count if paddingZeros > sc { self += Digits(repeating: 0, count: paddingZeros &- sc) } if paddingZeros >= sc { self += [addendLow, addendHigh]; return } // Now, i < sc var i = paddingZeros var newLimb: Limb var ovfl1: Bool (self[i], ovfl1) = self[i].addingReportingOverflow(addendLow) i += 1 if i == sc { newLimb = addendHigh &+ (ovfl1 ? 1 : 0) self.append(newLimb) if newLimb == 0 { self.append(1) } return } // Still, i < sc var ovfl2: Bool (self[i], ovfl2) = self[i].addingReportingOverflow(addendHigh) if ovfl1 { self[i] = self[i] &+ 1 if self[i] == 0 { ovfl2 = true } } while ovfl2 { i += 1 if i == sc { self.append(1); return } (self[i], ovfl2) = self[i].addingReportingOverflow(1) } } // // // MARK: - Limbs Subtraction // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Limbs Subtraction ||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // /// Calculates difference between Limbs in left limb mutating func difference(_ subtrahend: Limbs) { var subtrahend = subtrahend // swap to get difference if self.lessThan(subtrahend) { swap(&self, &subtrahend) } let rhc = subtrahend.count var ovfl = false var i = 0 // skip first zeros while i < rhc && subtrahend[i] == 0 { i += 1 } while i < rhc { if ovfl { (self[i], ovfl) = self[i].subtractingReportingOverflow(subtrahend[i]) self[i] = self[i] &- 1 ovfl = ovfl || self[i] == Limb.max } else { (self[i], ovfl) = self[i].subtractingReportingOverflow(subtrahend[i]) } i += 1 } while ovfl { if i >= self.count { self.append(Limb.max) break } (self[i], ovfl) = self[i].subtractingReportingOverflow(1) i += 1 } if self.count > 1 && self.last! == 0 // cut excess zeros if required { var j = self.count - 2 while j >= 1 && self[j] == 0 { j -= 1 } self.removeSubrange((j + 1).. Limbs { var res = self res.difference(subtrahend) return res } // // // MARK: - Limbs Multiplication // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Limbs Multiplication ||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // mutating func addProductOf( multiplier: Limbs, multiplicand: Limbs ) { let (mpc, mcc) = (multiplier.count, multiplicand.count) self.reserveCapacity(mpc + mcc) // Minimize array subscript calls var l, r, mulHi, mulLo: Limb for i in 0.. Limbs { var res: Limbs = [0] res.addProductOf(multiplier: self, multiplicand: multiplicand) return res } func squared() -> Limbs { var res: Limbs = [0] res.reserveCapacity(2 * self.count) // Minimize array subscript calls var l, r, mulHi, mulLo: Limb for i in 0.. Limbs { if exponent == 0 { return [1] } if exponent == 1 { return self } var base = self var exponent = exponent var y: Limbs = [1] while exponent > 1 { if exponent & 1 != 0 { y = y.multiplyingBy(base) } base = base.squared() exponent >>= 1 } return base.multiplyingBy(y) } /// Calculate (n + 1) * (n + 2) * ... * (k - 1) * k static func recursiveMul(_ n: Limb, _ k: Limb) -> Limbs { if n >= k - 1 { return [k] } let m = (n + k) >> 1 return recursiveMul(n, m).multiplyingBy(recursiveMul(m, k)) } func factorial(_ base: Int) -> BInt { return BInt(limbs: Limbs.recursiveMul(0, Limb(base))) } // // // MARK: - Limbs Division and Modulo // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Limbs Division and Modulo ||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // /// An O(n) division algorithm that returns quotient and remainder. func divMod(_ divisor: Limbs) -> (quotient: Limbs, remainder: Limbs) { precondition(!divisor.equalTo(0), "Division or Modulo by zero not allowed") if self.equalTo(0) { return ([0], [0]) } var (quotient, remainder): (Limbs, Limbs) = ([0], [0]) var (previousCarry, carry, ele): (Limb, Limb, Limb) = (0, 0, 0) // bits of lhs minus one bit var i = (64 * (self.count - 1)) + Int(log2(Double(self.last!))) while i >= 0 { // shift remainder by 1 to the left for r in 0..> 63 ele <<= 1 ele |= previousCarry // carry from last step previousCarry = carry remainder[r] = ele } if previousCarry != 0 { remainder.append(previousCarry) } remainder.setBit(at: 0, to: self.getBit(at: i)) if !remainder.lessThan(divisor) { remainder.difference(divisor) quotient.setBit(at: i, to: true) } i -= 1 } return (quotient, remainder) } /// Division with limbs, result is floored to nearest whole number. func dividing(_ divisor: Limbs) -> Limbs { return self.divMod(divisor).quotient } /// Modulo with limbs, result is floored to nearest whole number. func modulus(_ divisor: Limbs) -> Limbs { return self.divMod(divisor).remainder } // // // MARK: - Limbs Comparing // ———————————————————————————————————————————————————————————————————————————————————————— // |||||||| Limbs Comparing ||||||||||||||||||||||||||||||||||||||||||||||||| // ———————————————————————————————————————————————————————————————————————————————————————— // // // // Note: // a < b iff b > a // a <= b iff b >= a // but: // a < b iff !(a >= b) // a <= b iff !(a > b) func lessThan(_ compare: Limbs) -> Bool { let lhsc = self.count let rhsc = compare.count if lhsc != rhsc { return lhsc < rhsc } var i = lhsc - 1 while i >= 0 { if self[i] != compare[i] { return self[i] < compare[i] } i -= 1 } return false // lhs == rhs } func equalTo(_ compare: Limb) -> Bool { return self[0] == compare && self.count == 1 } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_0NOTEQUAL.swift ================================================ // // OP_0NOTEQUAL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // replaces number with True if it's not zero, False otherwise. public struct OP0NotEqual: OpCodeProtocol { public var value: UInt8 { return 0x92 } public var name: String { return "OP_0NOTEQUAL" } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() context.pushToStack(input != 0) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_1ADD.swift ================================================ // // OP_1ADD.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // 1 is added to the input. public struct Op1Add: OpCodeProtocol { public var value: UInt8 { return 0x8b } public var name: String { return "OP_1ADD" } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() try context.pushToStack(input + 1) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_1SUB.swift ================================================ // // OP_1SUB.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // 1 is subtracted from the input. public struct Op1Sub: OpCodeProtocol { public var value: UInt8 { return 0x8c } public var name: String { return "OP_1SUB" } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() try context.pushToStack(input - 1) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_2DIV.swift ================================================ // // OP_2DIV.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The input is divided by 2. disabled. public struct Op2Div: OpCodeProtocol { public var value: UInt8 { return 0x8e } public var name: String { return "OP_2DIV" } public func isEnabled() -> Bool { return false } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() try context.pushToStack(input / 2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_2MUL.swift ================================================ // // OP_2MUL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The input is multiplied by 2. disabled. public struct Op2Mul: OpCodeProtocol { public var value: UInt8 { return 0x8d } public var name: String { return "OP_2MUL" } public func isEnabled() -> Bool { return false } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() try context.pushToStack(input * 2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_ABS.swift ================================================ // // OP_ABS.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // replaces number with its absolute value public struct OpAbsolute: OpCodeProtocol { public var value: UInt8 { return 0x90 } public var name: String { return "OP_ABS" } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() try context.pushToStack(abs(input)) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_ADD.swift ================================================ // // OP_ADD.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // (x y -- x+y) public struct OpAdd: OpCodeProtocol { public var value: UInt8 { return 0x93 } public var name: String { return "OP_ADD" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() try context.pushToStack(x1 + x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_BOOLAND.swift ================================================ // // OP_BOOLAND.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // If both a and b are not "" (null string), the output is 1. Otherwise 0. public struct OpBoolAnd: OpCodeProtocol { public var value: UInt8 { return 0x9a } public var name: String { return "OP_BOOLAND" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = context.data(at: -2) let x2 = context.data(at: -1) let output: Bool = x1 != Data() && x2 != Data() context.stack.removeLast() context.stack.removeLast() context.pushToStack(output) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_BOOLOR.swift ================================================ // // OP_BOOLOR.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // If a or b is not "" (null string), the output is 1. Otherwise 0. public struct OpBoolOr: OpCodeProtocol { public var value: UInt8 { return 0x9b } public var name: String { return "OP_BOOLOR" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = context.data(at: -2) let x2 = context.data(at: -1) let output: Bool = x1 != Data() || x2 != Data() context.stack.removeLast() context.stack.removeLast() context.pushToStack(output) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_DIV.swift ================================================ // // OP_DIV.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // (x y -- x/y) public struct OpDiv: OpCodeProtocol { public var value: UInt8 { return 0x96 } public var name: String { return "OP_DIV" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) // denominator must not be 0 guard x2 != 0 else { throw OpCodeExecutionError.error("Division by zero error") } context.stack.removeLast() context.stack.removeLast() try context.pushToStack(x1 / x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_GREATERTHAN.swift ================================================ // // OP_GREATERTHAN.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns 1 if x1 is greater than x2, 0 otherwise. public struct OpGreaterThan: OpCodeProtocol { public var value: UInt8 { return 0xa0 } public var name: String { return "OP_GREATERTHAN" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() context.pushToStack(x1 > x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_GREATERTHANOREQUAL.swift ================================================ // // OP_GREATERTHANOREQUAL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns 1 if x1 is greater than or equal to x2, 0 otherwise. public struct OpGreaterThanOrEqual: OpCodeProtocol { public var value: UInt8 { return 0xa2 } public var name: String { return "OP_GREATERTHANOREQUAL" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() context.pushToStack(x1 >= x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_LESSTHAN.swift ================================================ // // OP_LESSTHAN.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns 1 if x1 is less than x2, 0 otherwise. public struct OpLessThan: OpCodeProtocol { public var value: UInt8 { return 0x9f } public var name: String { return "OP_LESSTHAN" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() context.pushToStack(x1 < x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_LESSTHANOREQUAL.swift ================================================ // // OP_LESSTHANOREQUAL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns 1 if x1 is less than or equal to x2, 0 otherwise. public struct OpLessThanOrEqual: OpCodeProtocol { public var value: UInt8 { return 0xa1 } public var name: String { return "OP_LESSTHANOREQUAL" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() context.pushToStack(x1 <= x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_LSHIFT.swift ================================================ // // OP_LSHIFT.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // (x y -- x< Bool { return false } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() try context.pushToStack(x1 << x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_MAX.swift ================================================ // // OP_MAX.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns the larger of a and b. public struct OpMax: OpCodeProtocol { public var value: UInt8 { return 0xa4 } public var name: String { return "OP_MAX" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() try context.pushToStack(max(x1, x2)) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_MIN.swift ================================================ // // OP_MIN.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns the smaller of a and b. public struct OpMin: OpCodeProtocol { public var value: UInt8 { return 0xa3 } public var name: String { return "OP_MIN" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() try context.pushToStack(min(x1, x2)) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_MOD.swift ================================================ // // OP_MOD.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // (x y -- x%y) public struct OpMod: OpCodeProtocol { public var value: UInt8 { return 0x97 } public var name: String { return "OP_MOD" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) // denominator must not be 0 guard x2 != 0 else { throw OpCodeExecutionError.error("Modulo by zero error") } context.stack.removeLast() context.stack.removeLast() try context.pushToStack(x1 % x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_MUL.swift ================================================ // // OP_MUL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // (x y -- x*y) disabled public struct OpMul: OpCodeProtocol { public var value: UInt8 { return 0x95 } public var name: String { return "OP_MUL" } public func isEnabled() -> Bool { return false } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() try context.pushToStack(x1 * x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_NEGATE.swift ================================================ // // OP_NEGATE.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // negates the number, pops it from stack and pushes result. public struct OpNegate: OpCodeProtocol { public var value: UInt8 { return 0x8f } public var name: String { return "OP_NEGATE" } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() try context.pushToStack(-input) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_NOT.swift ================================================ // // OP_NOT.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // replaces number with True if it's zero, False otherwise. public struct OpNot: OpCodeProtocol { public var value: UInt8 { return 0x91 } public var name: String { return "OP_NOT" } // (in -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let input = try context.number(at: -1) context.stack.removeLast() context.pushToStack(input == 0) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_NUMEQUAL.swift ================================================ // // OP_NUMEQUAL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns 1 if the numbers are equal, 0 otherwise. public struct OpNumEqual: OpCodeProtocol { public var value: UInt8 { return 0x9c } public var name: String { return "OP_NUMEQUAL" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() context.pushToStack(x1 == x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_NUMEQUALVERIFY.swift ================================================ // // OP_NUMEQUALVERIFY.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Same as OP_NUMEQUAL, but runs OP_VERIFY afterward. public struct OpNumEqualVerify: OpCodeProtocol { public var value: UInt8 { return 0x9d } public var name: String { return "OP_NUMEQUALVERIFY" } // input : x1 x2 // output : - / fail public func mainProcess(_ context: ScriptExecutionContext) throws { try OpCode.OP_NUMEQUAL.mainProcess(context) do { try OpCode.OP_VERIFY.mainProcess(context) } catch { throw OpCodeExecutionError.error("OP_NUMEQUALVERIFY failed.") } } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_NUMNOTEQUAL.swift ================================================ // // OP_NUMNOTEQUAL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns 1 if the numbers are not equal, 0 otherwise. public struct OpNumNotEqual: OpCodeProtocol { public var value: UInt8 { return 0xe } public var name: String { return "OP_NUMNOTEQUAL" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() context.pushToStack(x1 != x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_RSHIFT.swift ================================================ // // OP_RSHIFT.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // (x y -- x>>y) disabled. public struct OpRShift: OpCodeProtocol { public var value: UInt8 { return 0x99 } public var name: String { return "OP_RSHIFT" } public func isEnabled() -> Bool { return false } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() try context.pushToStack(x1 >> x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_SUB.swift ================================================ // // OP_SUB.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // (x y -- x-y) public struct OpSub: OpCodeProtocol { public var value: UInt8 { return 0x94 } public var name: String { return "OP_SUB" } // (x1 x2 -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1 = try context.number(at: -2) let x2 = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() try context.pushToStack(x1 - x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Arithmetic/OP_WITHIN.swift ================================================ // // OP_WITHIN.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. public struct OpWithin: OpCodeProtocol { public var value: UInt8 { return 0xa5 } public var name: String { return "OP_WITHIN" } // (x1 min max -- out) public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(3) let x = try context.number(at: -3) let minValue = try context.number(at: -2) let maxValue = try context.number(at: -1) context.stack.removeLast() context.stack.removeLast() context.stack.removeLast() context.pushToStack(minValue <= x && x < maxValue) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Bitwise Logic/OP_AND.swift ================================================ // // OP_AND.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Boolean AND between each bit of the inputs public struct OpAnd: OpCodeProtocol { public var value: UInt8 { return 0x84 } public var name: String { return "OP_AND" } // input : x1 x2 // output : out public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x2 = context.stack.removeLast() let x1 = context.stack.removeLast() // Inputs must be the same size guard x1.count == x2.count else { throw OpCodeExecutionError.error("Invalid operand size") } let count: Int = x1.count var output = Data(count: count) for i in 0.. Bool { return false } // input : in // output : out public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let x = context.stack.removeLast() let output: Data = Data(from: x.map { ~$0 }) context.stack.append(output) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Bitwise Logic/OP_OR.swift ================================================ // // OP_OR.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Boolean OR between each bit of the inputs public struct OpOr: OpCodeProtocol { public var value: UInt8 { return 0x85 } public var name: String { return "OP_OR" } // input : x1 x2 // output : out public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x2 = context.stack.removeLast() let x1 = context.stack.removeLast() // Inputs must be the same size guard x1.count == x2.count else { throw OpCodeExecutionError.error("Invalid operand size") } let count: Int = x1.count var output = Data(count: count) for i in 0.. pub1 pub2 // output : true / false public func mainProcess(_ context: ScriptExecutionContext) throws { // Get numPublicKeys with validation try context.assertStackHeightGreaterThanOrEqual(1) let numPublicKeys = Int(try context.number(at: -1)) guard numPublicKeys >= 0 && numPublicKeys <= BTC_MAX_KEYS_FOR_CHECKMULTISIG else { throw OpCodeExecutionError.error("Invalid number of keys for \(name): \(numPublicKeys).") } try context.incrementOpCount(by: numPublicKeys) context.stack.removeLast() // Get pubkeys with validation var publicKeys: [Data] = [] try context.assertStackHeightGreaterThanOrEqual(numPublicKeys) for _ in 0..= 0 && numSigs <= numPublicKeys else { throw OpCodeExecutionError.error("Invalid number of signatures for \(name): \(numSigs).") } context.stack.removeLast() // Get sigs with validation var signatures: [Data] = [] try context.assertStackHeightGreaterThanOrEqual(numSigs) for _ in 0.. pub1 pub2 // output : Nothing / fail public func mainProcess(_ context: ScriptExecutionContext) throws { try OpCode.OP_CHECKMULTISIG.mainProcess(context) do { try OpCode.OP_VERIFY.mainProcess(context) } catch { throw OpCodeExecutionError.error("OP_CHECKMULTISIGVERIFY failed.") } } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_CHECKSIG.swift ================================================ // // OP_CHECKSIG.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. public struct OpCheckSig: OpCodeProtocol { public var value: UInt8 { return 0xac } public var name: String { return "OP_CHECKSIG" } // input : sig pubkey // output : true / false public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let pubkeyData: Data = context.stack.removeLast() let sigData: Data = context.stack.removeLast() guard let tx = context.transaction, let utxo = context.utxoToVerify else { throw OpCodeExecutionError.error("The transaction or the utxo to verify is not set.") } let valid = try Crypto.verifySigData(for: tx, inputIndex: Int(context.inputIndex), utxo: utxo, sigData: sigData, pubKeyData: pubkeyData) context.pushToStack(valid) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_CHECKSIGVERIFY.swift ================================================ // // OP_CHECKSIGVERIFY.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Same as OP_CHECKSIG, but OP_VERIFY is executed afterward. public struct OpCheckSigVerify: OpCodeProtocol { public var value: UInt8 { return 0xad } public var name: String { return "OP_CHECKSIGVERIFY" } // input : sig pubkey // output : Nothing / fail public func mainProcess(_ context: ScriptExecutionContext) throws { try OpCode.OP_CHECKSIG.mainProcess(context) do { try OpCode.OP_VERIFY.mainProcess(context) } catch { throw OpCodeExecutionError.error("OP_CHECKSIGVERIFY failed.") } } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_CODESEPARATOR.swift ================================================ // // OP_CODESEPARATOR.swift // BitcoinKit // // Created by Shun Usami on 2018/08/09. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation // All of the signature checking words will only match signatures to the data after the most recently-executed OP_CODESEPARATOR. public struct OpCodeSeparator: OpCodeProtocol { public var value: UInt8 { return 0xab } public var name: String { return "OP_CODESEPARATOR" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_HASH160.swift ================================================ // // OP_HASH160.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The input is hashed twice: first with SHA-256 and then with RIPEMD-160. public struct OpHash160: OpCodeProtocol { public var value: UInt8 { return 0xa9 } public var name: String { return "OP_HASH160" } // input : in // output : hash public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let data: Data = context.stack.removeLast() let hash = RIPEMD160.hash(data.sha256()) context.stack.append(hash) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_HASH256.swift ================================================ // // OP_HASH256.swift // BitcoinKit // // Created by Shun Usami on 2018/08/09. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation // The input is hashed two times with SHA-256. public struct OpHash256: OpCodeProtocol { public var value: UInt8 { return 0xaa } public var name: String { return "OP_HASH256" } // input : in // output : hash public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let data: Data = context.stack.removeLast() let hash: Data = data.doubleSHA256 context.stack.append(hash) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_RIPEMD160.swift ================================================ // // OP_RIPEMD160.swift // BitcoinKit // // Created by Shun Usami on 2018/08/09. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation // The input is hashed using RIPEMD-160. public struct OpRipemd160: OpCodeProtocol { public var value: UInt8 { return 0xa6 } public var name: String { return "OP_RIPEMD160" } // input : in // output : hash public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let data: Data = context.stack.removeLast() let hash: Data = RIPEMD160.hash(data) context.stack.append(hash) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_SHA1.swift ================================================ // // OP_SHA1.swift // BitcoinKit // // Created by Shun Usami on 2018/08/09. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation import CryptoSwift // The input is hashed using SHA-1. public struct OpSha1: OpCodeProtocol { public var value: UInt8 { return 0xa7 } public var name: String { return "OP_SHA1" } // input : in // output : hash public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let data: Data = context.stack.removeLast() let hash: Data = data.sha1() context.stack.append(hash) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Crypto/OP_SHA256.swift ================================================ // // OP_SHA256.swift // BitcoinKit // // Created by Shun Usami on 2018/08/09. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation // The input is hashed using SHA-256. public struct OpSha256: OpCodeProtocol { public var value: UInt8 { return 0xa8 } public var name: String { return "OP_SHA256" } // input : in // output : hash public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let data: Data = context.stack.removeLast() let hash: Data = data.sha256() context.stack.append(hash) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_ELSE.swift ================================================ // // OP_ELSE.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation public struct OpElse: OpCodeProtocol { public var value: UInt8 { return 0x67 } public var name: String { return "OP_ELSE" } public func mainProcess(_ context: ScriptExecutionContext) throws { guard !context.conditionStack.isEmpty else { throw OpCodeExecutionError.error("Expected an OP_IF or OP_NOTIF branch before OP_ELSE.") } let f = context.conditionStack.removeLast() context.conditionStack.append(!f) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_ENDIF.swift ================================================ // // OP_ENDIF.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation public struct OpEndIf: OpCodeProtocol { public var value: UInt8 { return 0x68 } public var name: String { return "OP_ENDIF" } public func mainProcess(_ context: ScriptExecutionContext) throws { guard !context.conditionStack.isEmpty else { throw OpCodeExecutionError.error("Expected an OP_IF or OP_NOTIF branch before OP_ENDIF.") } context.conditionStack.removeLast() } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_IF.swift ================================================ // // OP_IF.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation public struct OpIf: OpCodeProtocol { public var value: UInt8 { return 0x63 } public var name: String { return "OP_IF" } public func mainProcess(_ context: ScriptExecutionContext) throws { var value: Bool = false if context.shouldExecute { try context.assertStackHeightGreaterThanOrEqual(1) value = context.bool(at: -1) context.stack.removeLast() } context.conditionStack.append(value) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_NOP.swift ================================================ // // OP_NOP.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation // do nothing public struct OpNop: OpCodeProtocol { public var value: UInt8 { return 0x61 } public var name: String { return "OP_NOP" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_NOTIF.swift ================================================ // // OP_NOTIF.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation public struct OpNotIf: OpCodeProtocol { public var value: UInt8 { return 0x64 } public var name: String { return "OP_NOTIF" } public func mainProcess(_ context: ScriptExecutionContext) throws { var value: Bool = false if context.shouldExecute { try context.assertStackHeightGreaterThanOrEqual(1) value = context.bool(at: -1) context.stack.removeLast() } context.conditionStack.append(!value) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_RETURN.swift ================================================ // // OP_RETURN.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public struct OpReturn: OpCodeProtocol { public var value: UInt8 { return 0x6a } public var name: String { return "OP_RETURN" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("OP_RETURN was encountered") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_VER.swift ================================================ // // OP_VER.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation public struct OpVer: OpCodeProtocol { public var value: UInt8 { return 0x62 } public var name: String { return "OP_VER" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("OP_VER should not be executed.") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_VERIF.swift ================================================ // // OP_VERIF.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation // Transaction is invalid unless occuring in an unexecuted OP_IF branch public struct OpVerIf: OpCodeProtocol { public var value: UInt8 { return 0x65 } public var name: String { return "OP_VERIF" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("OP_VERIF should not be executed.") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_VERIFY.swift ================================================ // // OP_VERIFY.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Marks transaction as invalid if top stack value is not true. The top stack value is removed. public struct OpVerify: OpCodeProtocol { public var value: UInt8 { return 0x69 } public var name: String { return "OP_VERIFY" } // input : true / false // output : - / fail public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) guard context.bool(at: -1) else { throw OpCodeExecutionError.error("OP_VERIFY failed.") } context.stack.removeLast() } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Flow Control/OP_VERNOTIF.swift ================================================ // // OP_VERNOTIF.swift // BitcoinKit // // Created by Shun Usami on 2018/08/08. // Copyright © 2018 BitcoinKit developers. All rights reserved. // import Foundation public struct OpVerNotIf: OpCodeProtocol { public var value: UInt8 { return 0x66 } public var name: String { return "OP_VERNOTIF" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("OP_VERNOTIF should not be executed.") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Lock Time/OP_CHECKLOCKTIMEVERIFY.swift ================================================ // // OP_CHECKLOCKTIMEVERIFY.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Marks transaction as invalid if the top stack item is greater than the transaction's nLockTime field, otherwise script evaluation continues as though an OP_NOP was executed. Transaction is also invalid if // 1. the stack is empty; or // 2. the top stack item is negative; or // 3. the top stack item is greater than or equal to 500000000 while the transaction's nLockTime field is less than 500000000, or vice versa; or // 4. the input's nSequence field is equal to 0xffffffff. // The precise semantics are described in BIP 0065. public struct OpCheckLockTimeVerify: OpCodeProtocol { public var value: UInt8 { return 0xb1 } public var name: String { return "OP_CHECKLOCKTIMEVERIFY " } // input : x // output : x / fail public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) // nLockTime should be Int5 // reference: https://github.com/Bitcoin-ABC/bitcoin-abc/blob/73c5e7532e19b8f35fcf73255cd1d0df67607cd2/src/script/interpreter.cpp#L420 let nLockTime = try context.number(at: -1) guard nLockTime >= 0 else { throw OpCodeExecutionError.error("NEGATIVE_LOCKTIME") } // checker.CheckLockTime(nLockTime) guard let tx = context.transaction, let txin = context.txinToVerify else { throw OpCodeExecutionError.error("OP_CHECKLOCKTIMEVERIFY must have a transaction in context.") } // There are two kinds of nLockTime: lock-by-blockheight and lock-by-blocktime, distinguished by whether nLockTime < LOCKTIME_THRESHOLD. // // We want to compare apples to apples, so fail the script unless the type of nLockTime being tested is the same as the nLockTime in the transaction. guard (tx.lockTime < BTC_LOCKTIME_THRESHOLD && nLockTime < BTC_LOCKTIME_THRESHOLD) || (tx.lockTime >= BTC_LOCKTIME_THRESHOLD && nLockTime >= BTC_LOCKTIME_THRESHOLD) else { throw OpCodeExecutionError.error("tx.lockTime and nLockTime should be the same kind.") } guard nLockTime <= tx.lockTime else { throw OpCodeExecutionError.error("The top stack item is greater than the transaction's nLockTime field") } // Finally the nLockTime feature can be disabled and thus // CHECKLOCKTIMEVERIFY bypassed if every txin has been finalized by setting // nSequence to maxint. The transaction would be allowed into the // blockchain, making the opcode ineffective. // // Testing if this vin is not final is sufficient to prevent this condition. // Alternatively we could test all inputs, but testing just this input // minimizes the data required to prove correct CHECKLOCKTIMEVERIFY // execution. let SEQUENCE_FINAL: UInt32 = 0xffffffff guard txin.sequence != SEQUENCE_FINAL else { throw OpCodeExecutionError.error("The input's nSequence field is equal to 0xffffffff.") } } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Lock Time/OP_CHECKSEQUENCEVERIFY.swift ================================================ // // OP_CHECKSEQUENCEVERIFY.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Marks transaction as invalid if the relative lock time of the input (enforced by BIP 0068 with nSequence) is not equal to or longer than the value of the top stack item. The precise semantics are described in BIP 0112. public struct OpCheckSequenceVerify: OpCodeProtocol { public var value: UInt8 { return 0xb2 } public var name: String { return "OP_CHECKSEQUENCEVERIFY" } // input : x // output : x / fail public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) // nLockTime should be Int5 // reference: https://github.com/Bitcoin-ABC/bitcoin-abc/blob/73c5e7532e19b8f35fcf73255cd1d0df67607cd2/src/script/interpreter.cpp#L420 let nSequenceTmp = try context.number(at: -1) guard nSequenceTmp >= 0 else { throw OpCodeExecutionError.error("NEGATIVE_LOCKTIME") } let nSequence: UInt32 = UInt32(nSequenceTmp) guard let tx = context.transaction, let txin = context.txinToVerify else { throw OpCodeExecutionError.error("OP_CHECKLOCKTIMEVERIFY must have a transaction in context.") } let txToSequence = txin.sequence guard tx.version > 1 else { throw OpCodeExecutionError.error("Transaction's version number is not set high enough to trigger BIP 68 rules.") } let SEQUENCE_LOCKTIME_DISABLE_FLAG: UInt32 = (1 << 31) guard txToSequence & SEQUENCE_LOCKTIME_DISABLE_FLAG == 0 else { throw OpCodeExecutionError.error("SEQUENCE_LOCKTIME_DISABLE_FLAG is set.") } let SEQUENCE_LOCKTIME_TYPE_FLAG: UInt32 = (1 << 22) let SEQUENCE_LOCKTIME_MASK: UInt32 = 0x0000ffff let nLockTimeMask: UInt32 = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK let txToSequenceMasked: UInt32 = txToSequence & nLockTimeMask let nSequenceMasked: UInt32 = nSequence & nLockTimeMask guard (txToSequenceMasked < SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < SEQUENCE_LOCKTIME_TYPE_FLAG) || (txToSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG) else { throw OpCodeExecutionError.error("txToSequenceMasked and nSequenceMasked should be the same kind.") } guard nSequence <= txToSequenceMasked else { throw OpCodeExecutionError.error("The top stack item is greater than the transaction's nSequence field") } } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/OP_EXAMPLE.swift ================================================ // // OP_EXAMPLE.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the “Software”), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // This class should be removed when all OP_CODEs are implemented public class OpExample: OpCodeProtocol { public var value: UInt8 { return 0x00 } public var name: String { return "OP_EXAMPLE" } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Pseudo Words/OP_INVALIDOPCODE.swift ================================================ // // OP_INVALIDOPCODE.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public struct OpInvalidOpCode: OpCodeProtocol { public var value: UInt8 { return 0xff } public var name: String { return "OP_INVALIDOPCODE" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("OP_INVALIDOPCODE should not be executed.") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Pseudo Words/OP_PUBKEY.swift ================================================ // // OP_PUBKEY.swift // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Represents a public key hashed with OP_HASH160. // This used internally for assisting with transaction matching. They are invalid if used in actual scripts. public struct OpPubkey: OpCodeProtocol { public var value: UInt8 { return 0xfe } public var name: String { return "OP_PUBKEY" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("OP_PUBKEY should not be executed.") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Pseudo Words/OP_PUBKEYHASH.swift ================================================ // // OP_PUBKEYHASH.swift // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Represents a public key compatible with OP_CHECKSIG. // This used internally for assisting with transaction matching. They are invalid if used in actual scripts. public struct OpPubkeyHash: OpCodeProtocol { public var value: UInt8 { return 0xfd } public var name: String { return "OP_PUBKEYHASH" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("OP_PUBKEYHASH should not be executed.") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Push Data/OP_0.swift ================================================ // // OP_0.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // An empty array of bytes is pushed onto the stack. // This is not a no-op, but is PUSHDATA op: an item is added to the stack. // public struct Op0: OpCodeProtocol { public var value: UInt8 { return 0x00 } public var name: String { return "OP_0" } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Push Data/OP_1NEGATE.swift ================================================ // // OP_1NEGATE.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The number -1 is pushed onto the stack. public struct Op1Negate: OpCodeProtocol { public var value: UInt8 { return 0x4f } public var name: String { return "OP_1NEGATE" } // input : - // output : -1 public func mainProcess(_ context: ScriptExecutionContext) throws { try context.pushToStack(-1) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Push Data/OP_N.swift ================================================ // // OP_N.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The number in the word name (1-16) is pushed onto the stack. public struct OpN: OpCodeProtocol { public var value: UInt8 { return 0x50 + n } public var name: String { return "OP_\(n)" } private let n: UInt8 internal init(_ n: UInt8) { guard (1...16).contains(n) else { fatalError("OP_N can be initialized with N between 1 and 16. \(n) is not valid.") } self.n = n } // input : - // output : n public func mainProcess(_ context: ScriptExecutionContext) throws { try context.pushToStack(Int32(n)) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Push Data/OP_PUSHDATA.swift ================================================ // // OP_PUSHDATA.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Any opcode with value < PUSHDATA1 is a length of the string to be pushed on the stack. // So opcode 0x01 is followed by 1 byte of data, 0x09 by 9 bytes and so on up to 0x4b (75 bytes) // PUSHDATA opcode is followed by N-byte length of the string that follows. // The next 1-byte contains the number of bytes to be pushed onto the stack (allows pushing 0..255 bytes). public struct OpPushData1: OpCodeProtocol { public var value: UInt8 { return 0x4c } public var name: String { return "OP_PUSHDATA1" } } // The next 2-bytes contain the number of bytes to be pushed onto the stack in little endian order (allows pushing 0..65535 bytes). public struct OpPushData2: OpCodeProtocol { public var value: UInt8 { return 0x4d } public var name: String { return "OP_PUSHDATA2" } } // The next 4-bytes contain the number of bytes to be pushed onto the stack in little endian order (allows pushing 0..4294967295 bytes) public struct OpPushData4: OpCodeProtocol { public var value: UInt8 { return 0x4e } public var name: String { return "OP_PUSHDATA4" } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Push Data/OP_RESERVED.swift ================================================ // // OP_RESERVED.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public struct OpReserved: OpCodeProtocol { public var value: UInt8 { return 0x50 } public var name: String { return "OP_RESERVED" } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.error("\(name) should not be executed.") } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Reserved Words/OP_NOPN.swift ================================================ // // OP_NOPN.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public struct OpNop1: OpCodeProtocol { public var value: UInt8 { return 0xb0 } public var name: String { return "OP_NOP1" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } public struct OpNop4: OpCodeProtocol { public var value: UInt8 { return 0xb3 } public var name: String { return "OP_NOP4" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } public struct OpNop5: OpCodeProtocol { public var value: UInt8 { return 0xb4 } public var name: String { return "OP_NOP5" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } public struct OpNop6: OpCodeProtocol { public var value: UInt8 { return 0xb5 } public var name: String { return "OP_NOP6" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } public struct OpNop7: OpCodeProtocol { public var value: UInt8 { return 0xb6 } public var name: String { return "OP_NOP8" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } public struct OpNop8: OpCodeProtocol { public var value: UInt8 { return 0xb7 } public var name: String { return "OP_NOP8" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } public struct OpNop9: OpCodeProtocol { public var value: UInt8 { return 0xb8 } public var name: String { return "OP_NOP9" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } public struct OpNop10: OpCodeProtocol { public var value: UInt8 { return 0xb9 } public var name: String { return "OP_NOP10" } public func mainProcess(_ context: ScriptExecutionContext) throws { // do nothing } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Splice/OP_BIN2NUM.swift ================================================ // // OP_BIN2NUM.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // convert byte sequence x into a numeric value public struct OpBin2Num: OpCodeProtocol { public var value: UInt8 { return 0x81 } public var name: String { return "OP_BIN2NUM" } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Splice/OP_CAT.swift ================================================ // // OP_CAT.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Concatenates two strings. public struct OpConcatenate: OpCodeProtocol { public var value: UInt8 { return 0x7e } public var name: String { return "OP_CAT" } // input : x1 x2 // output : out public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x1: Data = context.data(at: -2) let x2: Data = context.data(at: -1) guard x1.count + x2.count <= BTC_MAX_SCRIPT_ELEMENT_SIZE else { throw OpCodeExecutionError.error("Push value size limit exceeded") } context.stack.removeLast() context.stack.removeLast() context.stack.append(x1 + x2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Splice/OP_NUM2BIN.swift ================================================ // // OP_NUM2BIN.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // convert numeric value a into byte sequence of length b public struct OpNum2Bin: OpCodeProtocol { public var value: UInt8 { return 0x80 } public var name: String { return "OP_NUM2BIN" } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Splice/OP_SIZE.swift ================================================ // // OP_SIZE.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Pushes the string length of the top element of the stack (without popping it). public struct OpSize: OpCodeProtocol { public var value: UInt8 { return 0x82 } public var name: String { return "OP_SIZE" } // input : in // output : in size public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let x: Data = context.data(at: -1) try context.pushToStack(Int32(x.count)) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Splice/OP_SPLIT.swift ================================================ // // OP_SPLIT.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Split the operand at the given position. public struct OpSplit: OpCodeProtocol { public var value: UInt8 { return 0x7f } public var name: String { return "OP_SPLIT" } // input : in position // output : x1 x2 public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let data: Data = context.data(at: -2) // Make sure the split point is apropriate. let position: Int32 = try context.number(at: -1) guard position <= data.count else { throw OpCodeExecutionError.error("Invalid OP_SPLIT range") } let n1: Data = data.subdata(in: 0.. public func mainProcess(_ context: ScriptExecutionContext) throws { let count: Int = context.stack.count try context.pushToStack(Int32(count)) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_DROP.swift ================================================ // // OP_DROP.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Removes the top stack item. public struct OpDrop: OpCodeProtocol { public var value: UInt8 { return 0x75 } public var name: String { return "OP_DROP" } // input : x // output : Nothing public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) context.stack.removeLast() } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_DUP.swift ================================================ // // OP_DUP.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Duplicates the top stack item. public struct OpDuplicate: OpCodeProtocol { public var value: UInt8 { return 0x76 } public var name: String { return "OP_DUP" } // input : x // output : x x public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let x: Data = context.data(at: -1) try context.pushToStack(x) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_FROMALTSTACK.swift ================================================ // // OP_FROMALTSTACK.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Puts the input onto the top of the main stack. Removes it from the alt stack. public struct OpFromAltStack: OpCodeProtocol { public var value: UInt8 { return 0x6c } public var name: String { return "OP_FROMALTSTACK" } // input : (alt)x // output : x public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertAltStackHeightGreaterThanOrEqual(1) let x: Data = context.altStack.removeLast() context.stack.append(x) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_IFDUP.swift ================================================ // // OP_IFDUP.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // If the top stack value is not 0, duplicate it. public struct OpIfDup: OpCodeProtocol { public var value: UInt8 { return 0x73 } public var name: String { return "OP_IFDUP" } // input : x // output : x / x x public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) if context.bool(at: -1) { context.stack.append(context.data(at: -1)) } } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_NIP.swift ================================================ // // OP_NIP.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Removes the second-to-top stack item. public struct OpNip: OpCodeProtocol { public var value: UInt8 { return 0x77 } public var name: String { return "OP_NIP" } // input : x1 x2 // output : x2 public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let count: Int = context.stack.count context.stack.remove(at: count - 2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_OVER.swift ================================================ // // OP_OVER.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Copies the second-to-top stack item to the top. public struct OpOver: OpCodeProtocol { public var value: UInt8 { return 0x78 } public var name: String { return "OP_OVER" } // input : x1 x2 // output : x1 x2 x1 public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x: Data = context.data(at: -2) context.stack.append(x) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_PICK.swift ================================================ // // OP_PICK.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The item n back in the stack is copied to the top. public struct OpPick: OpCodeProtocol { public var value: UInt8 { return 0x79 } public var name: String { return "OP_PICK" } // input : xn ... x2 x1 x0 // output : xn ... x2 x1 x0 xn public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let n: Int32 = try context.number(at: -1) context.stack.removeLast() guard n >= 0 else { throw OpCodeExecutionError.error("\(name): n should be greater than or equal to 0.") } let index: Int = Int(n + 1) try context.assertStackHeightGreaterThanOrEqual(index) let xn: Data = context.data(at: -index) context.stack.append(xn) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_ROLL.swift ================================================ // // OP_ROLL.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The item n back in the stack is moved to the top. public struct OpRoll: OpCodeProtocol { public var value: UInt8 { return 0x7a } public var name: String { return "OP_ROLL" } // input : xn ... x2 x1 x0 // output : ... x2 x1 x0 xn public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let n: Int32 = try context.number(at: -1) context.stack.removeLast() guard n >= 0 else { throw OpCodeExecutionError.error("\(name): n should be greater than or equal to 0.") } let index: Int = Int(n + 1) try context.assertStackHeightGreaterThanOrEqual(index) let count: Int = context.stack.count let xn: Data = context.stack.remove(at: count - index) context.stack.append(xn) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_ROT.swift ================================================ // // OP_ROT.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The top three items on the stack are rotated to the left. public struct OpRot: OpCodeProtocol { public var value: UInt8 { return 0x7b } public var name: String { return "OP_ROT" } // input : x1 x2 x3 // output : x2 x3 x1 public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(3) context.swapDataAt(i: -3, j: -2) context.swapDataAt(i: -2, j: -1) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_SWAP.swift ================================================ // // OP_SWAP.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The top two items on the stack are swapped. public struct OpSwap: OpCodeProtocol { public var value: UInt8 { return 0x7c } public var name: String { return "OP_SWAP" } // input : x1 x2 // output : x2 x1 public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) context.swapDataAt(i: -2, j: -1) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_TOTALSTACK.swift ================================================ // // OP_TOALTSTACK.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // Puts the input onto the top of the alt stack. Removes it from the main stack. public struct OpToAltStack: OpCodeProtocol { public var value: UInt8 { return 0x6b } public var name: String { return "OP_TOALTSTACK" } // input : x // output : (alt)x public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(1) let x: Data = context.stack.removeLast() context.altStack.append(x) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OP_CODE/Stack/OP_TUCK.swift ================================================ // // OP_TUCK.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation // The item at the top of the stack is copied and inserted before the second-to-top item. public struct OpTuck: OpCodeProtocol { public var value: UInt8 { return 0x7d } public var name: String { return "OP_TUCK" } // input : x1 x2 // output : x2 x1 x2 public func mainProcess(_ context: ScriptExecutionContext) throws { try context.assertStackHeightGreaterThanOrEqual(2) let x: Data = context.data(at: -1) let count: Int = context.stack.count context.stack.insert(x, at: count - 2) } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OpCodeFactory.swift ================================================ // // OpCodeFactory.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation /** This struct represents a factory that creates OpCodes from integers or strings. */ public struct OpCodeFactory { /** Returns the OpCode which a given UInt8 value. Returns OP_INVALIDOPCODE for outranged value. - parameter value: UInt8 value corresponding to the OpCode - returns: The OpCode corresponding to value */ public static func get(with value: UInt8) -> OpCode { guard let item = (OpCode.list.first { $0.value == value }) else { return .OP_INVALIDOPCODE } return item } /** Returns the OpCode which a given name. Returns OP_INVALIDOPCODE for unknown names. - parameter name: String corresponding to the OpCode - returns: The OpCode corresponding to name */ public static func get(with name: String) -> OpCode { guard let item = (OpCode.list.first { $0.name == name }) else { return .OP_INVALIDOPCODE } return item } /** Returns OP_1NEGATE, OP_0 .. OP_16 for ints from -1 to 16. Returns OP_INVALIDOPCODE for other ints. - parameter smallInteger: Int value from -1 to 16 - returns: The OpCode corresponding to smallInteger */ public typealias SmallInteger = Int public static func opcode(for smallInteger: SmallInteger) -> OpCode { switch smallInteger { case -1: return .OP_1NEGATE case 0: return .OP_0 case 1...16: return get(with: OpCode.OP_1.value + UInt8(smallInteger - 1)) default: return .OP_INVALIDOPCODE } } /** Converts opcode OP_ or OP_1NEGATE to an Int value. If incorrect opcode is given, Int.max is returned. - parameter opcode: OpCode which can be OP_ or OP_1NEGATE - returns: Int value correspondint to OpCode */ public static func smallInteger(from opcode: OpCode) -> SmallInteger { switch opcode { case .OP_1NEGATE: return -1 case .OP_0: return 0 case (OpCode.OP_1)...(OpCode.OP_16): return Int(opcode.value - OpCode.OP_1.value + 1) default: return Int.max } } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/OpCodeProtocol.swift ================================================ // // OpCodeProtocol.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public protocol OpCodeProtocol { var name: String { get } var value: UInt8 { get } func isEnabled() -> Bool func mainProcess(_ context: ScriptExecutionContext) throws } extension OpCodeProtocol { public func isEnabled() -> Bool { return true } private func preprocess(_ context: ScriptExecutionContext) throws { if value > OpCode.OP_16 { try context.incrementOpCount() } guard isEnabled() else { throw OpCodeExecutionError.disabled } guard !(context.shouldExecute && 0 <= value && value <= OpCode.OP_PUSHDATA4.value) else { throw OpCodeExecutionError.error("PUSHDATA OP_CODE should not be executed.") } } public func mainProcess(_ context: ScriptExecutionContext) throws { throw OpCodeExecutionError.notImplemented("[\(name)(\(value))]") } public func execute(_ context: ScriptExecutionContext) throws { try preprocess(context) guard context.shouldExecute || (OpCode.OP_IF <= self && self <= OpCode.OP_ENDIF) else { if context.verbose { print("[SKIP execution : \(name)(\(value))]\n" + String(repeating: "-", count: 100)) } return } if context.verbose { print("OpCount : \(context.opCount)\n[pre execution : \(name)(\(value))]\n\(context)") } try mainProcess(context) if context.verbose { print("[post execution : \(name)(\(value))]\n\(context)\n" + String(repeating: "-", count: 100)) } } } public enum OpCodeExecutionError: Error { case notImplemented(String) case error(String) case opcodeRequiresItemsOnStack(Int) case invalidBignum case disabled } // == public func == (lhs: OpCodeProtocol, rhs: OpCodeProtocol) -> Bool { return lhs.value == rhs.value } public func == (lhs: OpCodeProtocol, rhs: Other) -> Bool { return lhs.value == rhs } public func == (lhs: Other, rhs: OpCodeProtocol) -> Bool { return lhs == rhs.value } // != public func != (lhs: OpCodeProtocol, rhs: OpCodeProtocol) -> Bool { return lhs.value != rhs.value } public func != (lhs: OpCodeProtocol, rhs: Other) -> Bool { return lhs.value != rhs } public func != (lhs: Other, rhs: OpCodeProtocol) -> Bool { return lhs != rhs.value } // > public func > (lhs: OpCodeProtocol, rhs: OpCodeProtocol) -> Bool { return lhs.value > rhs.value } public func > (lhs: OpCodeProtocol, rhs: Other) -> Bool { return lhs.value > rhs } public func > (lhs: Other, rhs: OpCodeProtocol) -> Bool { return lhs > rhs.value } // < public func < (lhs: OpCodeProtocol, rhs: OpCodeProtocol) -> Bool { return lhs.value < rhs.value } public func < (lhs: OpCodeProtocol, rhs: Other) -> Bool { return lhs.value < rhs } public func < (lhs: Other, rhs: OpCodeProtocol) -> Bool { return lhs < rhs.value } // >= public func >= (lhs: OpCodeProtocol, rhs: OpCodeProtocol) -> Bool { return lhs.value >= rhs.value } // <= public func <= (lhs: OpCodeProtocol, rhs: OpCodeProtocol) -> Bool { return lhs.value <= rhs.value } // ... public func ... (lhs: OpCodeProtocol, rhs: OpCodeProtocol) -> Range { return Range(lhs.value...rhs.value) } // ~= public func ~= (pattern: OpCodeProtocol, op: OpCodeProtocol) -> Bool { return pattern == op } public func ~= (pattern: Range, op: OpCodeProtocol) -> Bool { return pattern ~= op.value } ================================================ FILE: HDWalletKit/Core/BitcoinScript/Opcode.swift ================================================ // // OpCode.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public enum OpCode: OpCodeProtocol { // swiftlint:disable:next line_length case OP_0, OP_FALSE, OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4, OP_1NEGATE, OP_RESERVED, OP_1, OP_TRUE, OP_2, OP_3, OP_4, OP_5, OP_6, OP_7, OP_8, OP_9, OP_10, OP_11, OP_12, OP_13, OP_14, OP_15, OP_16, OP_NOP, OP_VER, OP_IF, OP_NOTIF, OP_VERIF, OP_VERNOTIF, OP_ELSE, OP_ENDIF, OP_VERIFY, OP_RETURN, OP_TOALTSTACK, OP_FROMALTSTACK, OP_2DROP, OP_2DUP, OP_3DUP, OP_2OVER, OP_2ROT, OP_2SWAP, OP_IFDUP, OP_DEPTH, OP_DROP, OP_DUP, OP_NIP, OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK, OP_CAT, OP_SIZE, OP_SPLIT, OP_NUM2BIN, OP_BIN2NUM, OP_INVERT, OP_AND, OP_OR, OP_XOR, OP_EQUAL, OP_EQUALVERIFY, OP_RESERVED1, OP_RESERVED2, OP_1ADD, OP_1SUB, OP_2MUL, OP_2DIV, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT, OP_BOOLAND, OP_BOOLOR, OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN, OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL, OP_MIN, OP_MAX, OP_WITHIN, OP_RIPEMD160, OP_SHA1, OP_SHA256, OP_HASH160, OP_HASH256, OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY, OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY, OP_PUBKEYHASH, OP_PUBKEY, OP_INVALIDOPCODE, OP_NOP1, OP_NOP4, OP_NOP5, OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10 private var opcode: OpCodeProtocol { switch self { // 1. Operators pushing data on stack. case .OP_0: return Op0() case .OP_FALSE: return OpCode.OP_0.opcode case .OP_PUSHDATA1: return OpPushData1() case .OP_PUSHDATA2: return OpPushData2() case .OP_PUSHDATA4: return OpPushData4() case .OP_1NEGATE: return Op1Negate() case .OP_RESERVED: return OpReserved() // reserved and fail if executed case .OP_1: return OpN(1) case .OP_TRUE: return OpCode.OP_1.opcode case .OP_2: return OpN(2) case .OP_3: return OpN(3) case .OP_4: return OpN(4) case .OP_5: return OpN(5) case .OP_6: return OpN(6) case .OP_7: return OpN(7) case .OP_8: return OpN(8) case .OP_9: return OpN(9) case .OP_10: return OpN(10) case .OP_11: return OpN(11) case .OP_12: return OpN(12) case .OP_13: return OpN(13) case .OP_14: return OpN(14) case .OP_15: return OpN(15) case .OP_16: return OpN(16) // 2. Flow Control operators case .OP_NOP: return OpNop() case .OP_VER: return OpVer() case .OP_IF: return OpIf() case .OP_NOTIF: return OpNotIf() case .OP_VERIF: return OpVerIf() case .OP_VERNOTIF: return OpVerNotIf() case .OP_ELSE: return OpElse() case .OP_ENDIF: return OpEndIf() case .OP_VERIFY: return OpVerify() case .OP_RETURN: return OpReturn() // 3. Stack ops case .OP_TOALTSTACK: return OpToAltStack() case .OP_FROMALTSTACK: return OpFromAltStack() case .OP_2DROP: return Op2Drop() case .OP_2DUP: return Op2Duplicate() case .OP_3DUP: return Op3Duplicate() case .OP_2OVER: return Op2Over() case .OP_2ROT: return Op2Rot() case .OP_2SWAP: return Op2Swap() case .OP_IFDUP: return OpIfDup() case .OP_DEPTH: return OpDepth() case .OP_DROP: return OpDrop() case .OP_DUP: return OpDuplicate() case .OP_NIP: return OpNip() case .OP_OVER: return OpOver() case .OP_PICK: return OpPick() case .OP_ROLL: return OpRoll() case .OP_ROT: return OpRot() case .OP_SWAP: return OpSwap() case .OP_TUCK: return OpTuck() // 4. Splice ops case .OP_CAT: return OpConcatenate() case .OP_SIZE: return OpSize() case .OP_SPLIT: return OpSplit() case .OP_NUM2BIN: return OpExample() case .OP_BIN2NUM: return OpExample() // 5. Bitwise logic case .OP_INVERT: return OpInvert() case .OP_AND: return OpAnd() case .OP_OR: return OpOr() case .OP_XOR: return OpXor() case .OP_EQUAL: return OpEqual() case .OP_EQUALVERIFY: return OpEqualVerify() case .OP_RESERVED1: return OpReserved1() // reserved and fail if executed case .OP_RESERVED2: return OpReserved2() // reserved and fail if executed // 6. Arithmetic case .OP_1ADD: return Op1Add() case .OP_1SUB: return Op1Sub() case .OP_2MUL: return Op2Mul() case .OP_2DIV: return Op2Div() case .OP_NEGATE: return OpNegate() case .OP_ABS: return OpAbsolute() case .OP_NOT: return OpNot() case .OP_0NOTEQUAL: return OP0NotEqual() case .OP_ADD: return OpAdd() case .OP_SUB: return OpSub() case .OP_MUL: return OpMul() case .OP_DIV: return OpDiv() case .OP_MOD: return OpMod() case .OP_LSHIFT: return OpLShift() case .OP_RSHIFT: return OpRShift() case .OP_BOOLAND: return OpBoolAnd() case .OP_BOOLOR: return OpBoolOr() case .OP_NUMEQUAL: return OpNumEqual() case .OP_NUMEQUALVERIFY: return OpNumEqualVerify() case .OP_NUMNOTEQUAL: return OpNumNotEqual() case .OP_LESSTHAN: return OpLessThan() case .OP_GREATERTHAN: return OpGreaterThan() case .OP_LESSTHANOREQUAL: return OpLessThanOrEqual() case .OP_GREATERTHANOREQUAL: return OpGreaterThanOrEqual() case .OP_MIN: return OpMin() case .OP_MAX: return OpMax() case .OP_WITHIN: return OpWithin() // Crypto case .OP_RIPEMD160: return OpRipemd160() case .OP_SHA1: return OpSha1() case .OP_SHA256: return OpSha256() case .OP_HASH160: return OpHash160() case .OP_HASH256: return OpHash256() case .OP_CODESEPARATOR: return OpCodeSeparator() case .OP_CHECKSIG: return OpCheckSig() case .OP_CHECKSIGVERIFY: return OpCheckSigVerify() case .OP_CHECKMULTISIG: return OpCheckMultiSig() case .OP_CHECKMULTISIGVERIFY: return OpCheckMultiSigVerify() // Lock Times case .OP_CHECKLOCKTIMEVERIFY: return OpCheckLockTimeVerify() // previously OP_NOP2 case .OP_CHECKSEQUENCEVERIFY: return OpCheckSequenceVerify() // previously OP_NOP3 // Pseudo Words case .OP_PUBKEYHASH: return OpPubkeyHash() case .OP_PUBKEY: return OpPubkey() case .OP_INVALIDOPCODE: return OpInvalidOpCode() // Reserved Words case .OP_NOP1: return OpNop1() case .OP_NOP4: return OpNop4() case .OP_NOP5: return OpNop5() case .OP_NOP6: return OpNop6() case .OP_NOP7: return OpNop7() case .OP_NOP8: return OpNop8() case .OP_NOP9: return OpNop9() case .OP_NOP10: return OpNop10() } } // swiftlint:disable:next line_length internal static let list: [OpCode] = [OP_0, OP_FALSE, OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4, OP_1NEGATE, OP_RESERVED, OP_1, OP_TRUE, OP_2, OP_3, OP_4, OP_5, OP_6, OP_7, OP_8, OP_9, OP_10, OP_11, OP_12, OP_13, OP_14, OP_15, OP_16, OP_NOP, OP_VER, OP_IF, OP_NOTIF, OP_VERIF, OP_VERNOTIF, OP_ELSE, OP_ENDIF, OP_VERIFY, OP_RETURN, OP_TOALTSTACK, OP_FROMALTSTACK, OP_2DROP, OP_2DUP, OP_3DUP, OP_2OVER, OP_2ROT, OP_2SWAP, OP_IFDUP, OP_DEPTH, OP_DROP, OP_DUP, OP_NIP, OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK, OP_CAT, OP_SIZE, OP_SPLIT, OP_NUM2BIN, OP_INVERT, OP_AND, OP_OR, OP_XOR, OP_EQUAL, OP_EQUALVERIFY, OP_RESERVED1, OP_RESERVED2, OP_BIN2NUM, OP_1ADD, OP_1SUB, OP_2MUL, OP_2DIV, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT, OP_BOOLAND, OP_BOOLOR, OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN, OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL, OP_MIN, OP_MAX, OP_WITHIN, OP_RIPEMD160, OP_SHA1, OP_SHA256, OP_HASH160, OP_HASH256, OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY, OP_CHECKLOCKTIMEVERIFY, OP_CHECKSEQUENCEVERIFY, OP_PUBKEYHASH, OP_PUBKEY, OP_INVALIDOPCODE, OP_NOP1, OP_NOP4, OP_NOP5, OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10] public var name: String { return opcode.name } public var value: UInt8 { return opcode.value } public func isEnabled() -> Bool { return opcode.isEnabled() } public func mainProcess(_ context: ScriptExecutionContext) throws { try opcode.mainProcess(context) } } //public struct OpCode { // // 1. Operators pushing data on stack. // // // Push 1 byte 0x00 on the stack // public static let OP_0: OpCodeProtocol = Op0() // public static let OP_FALSE = OP_0 // // // Any opcode with value < PUSHDATA1 is a length of the string to be pushed on the stack. // // So opcode 0x01 is followed by 1 byte of data, 0x09 by 9 bytes and so on up to 0x4b (75 bytes) // // // PUSHDATA opcode is followed by N-byte length of the string that follows. // public static let OP_PUSHDATA1: OpCodeProtocol = OpPushData1() // followed by a 1-byte length of the string to push (allows pushing 0..255 bytes). // public static let OP_PUSHDATA2: OpCodeProtocol = OpPushData2() // followed by a 2-byte length of the string to push (allows pushing 0..65535 bytes). // public static let OP_PUSHDATA4: OpCodeProtocol = OpPushData4() // followed by a 4-byte length of the string to push (allows pushing 0..4294967295 bytes). // public static let OP_1NEGATE: OpCodeProtocol = Op1Negate() // pushes -1 number on the stack // public static let OP_RESERVED: OpCodeProtocol = OpExample() // Not assigned. If executed, transaction is invalid. // // // public static let OP_ pushes number on the stack // public static let OP_1: OpCodeProtocol = OpN(1) // public static let OP_TRUE = OP_1 // public static let OP_2: OpCodeProtocol = OpN(2) // public static let OP_3: OpCodeProtocol = OpN(3) // public static let OP_4: OpCodeProtocol = OpN(4) // public static let OP_5: OpCodeProtocol = OpN(5) // public static let OP_6: OpCodeProtocol = OpN(6) // public static let OP_7: OpCodeProtocol = OpN(7) // public static let OP_8: OpCodeProtocol = OpN(8) // public static let OP_9: OpCodeProtocol = OpN(9) // public static let OP_10: OpCodeProtocol = OpN(10) // public static let OP_11: OpCodeProtocol = OpN(11) // public static let OP_12: OpCodeProtocol = OpN(12) // public static let OP_13: OpCodeProtocol = OpN(13) // public static let OP_14: OpCodeProtocol = OpN(14) // public static let OP_15: OpCodeProtocol = OpN(15) // public static let OP_16: OpCodeProtocol = OpN(16) // // // 2. Control flow operators // // public static let OP_NOP: OpCodeProtocol = OpExample() // Does nothing // public static let OP_VER: OpCodeProtocol = OpExample() // Not assigned. If executed, transaction is invalid. // // // BitcoinQT executes all operators from public static let OP_IF to public static let OP_ENDIF even inside "non-executed" branch (to keep track of nesting). // // Since public static let OP_VERIF and public static let OP_VERNOTIF are not assigned, even inside a non-executed branch they will fall in "default:" switch case // // and cause the script to fail. Some other ops like public static let OP_VER can be present inside non-executed branch because they'll be skipped. // public static let OP_IF: OpCodeProtocol = OpExample() // If the top stack value is not 0, the statements are executed. The top stack value is removed. // public static let OP_NOTIF: OpCodeProtocol = OpExample() // If the top stack value is 0, the statements are executed. The top stack value is removed. // public static let OP_VERIF: OpCodeProtocol = OpExample() // Not assigned. Script is invalid with that opcode (even if inside non-executed branch). // public static let OP_VERNOTIF: OpCodeProtocol = OpExample() // Not assigned. Script is invalid with that opcode (even if inside non-executed branch). // public static let OP_ELSE: OpCodeProtocol = OpExample() // Executes code if the previous public static let OP_IF or public static let OP_NOTIF was not executed. // public static let OP_ENDIF: OpCodeProtocol = OpExample() // Finishes if/else block // // public static let OP_VERIFY: OpCodeProtocol = OpVerify() // Removes item from the stack if it's not 0x00 or 0x80 (negative zero). Otherwise, marks script as invalid. // public static let OP_RETURN: OpCodeProtocol = OpReturn() // Marks transaction as invalid. // // // Stack ops // public static let OP_TOALTSTACK: OpCodeProtocol = OpExample() // Moves item from the stack to altstack // public static let OP_FROMALTSTACK: OpCodeProtocol = OpExample() // Moves item from the altstack to stack // public static let OP_2DROP: OpCodeProtocol = OpExample() // public static let OP_2DUP: OpCodeProtocol = OpExample() // public static let OP_3DUP: OpCodeProtocol = OpExample() // public static let OP_2OVER: OpCodeProtocol = OpExample() // public static let OP_2ROT: OpCodeProtocol = OpExample() // public static let OP_2SWAP: OpCodeProtocol = OpExample() // public static let OP_IFDUP: OpCodeProtocol = OpExample() // public static let OP_DEPTH: OpCodeProtocol = OpExample() // public static let OP_DROP: OpCodeProtocol = OpExample() // public static let OP_DUP: OpCodeProtocol = OpDuplicate() // public static let OP_NIP: OpCodeProtocol = OpExample() // public static let OP_OVER: OpCodeProtocol = OpExample() // public static let OP_PICK: OpCodeProtocol = OpExample() // public static let OP_ROLL: OpCodeProtocol = OpExample() // public static let OP_ROT: OpCodeProtocol = OpExample() // public static let OP_SWAP: OpCodeProtocol = OpSwap() // public static let OP_TUCK: OpCodeProtocol = OpExample() // // // Splice ops // public static let OP_CAT: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_SUBSTR: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_LEFT: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_RIGHT: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_SIZE: OpCodeProtocol = OpExample() // // // Bit logic // public static let OP_INVERT: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_AND: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_OR: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_XOR: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // // public static let OP_EQUAL: OpCodeProtocol = OpEqual() // Last two items are removed from the stack and compared. Result (true or false) is pushed to the stack. // public static let OP_EQUALVERIFY: OpCodeProtocol = OpEqualVerify() // Same as public static let OP_EQUAL, but removes the result from the stack if it's true or marks script as invalid. // // public static let OP_RESERVED1: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // public static let OP_RESERVED2: OpCodeProtocol = OpExample() // Disabled opcode. If executed, transaction is invalid. // // // Numeric // public static let OP_1ADD: OpCodeProtocol = Op1Add() // adds 1 to last item, pops it from stack and pushes result. // public static let OP_1SUB: OpCodeProtocol = Op1Sub() // substracts 1 to last item, pops it from stack and pushes result. // public static let OP_2MUL: OpCodeProtocol = Op2Mul() // Disabled opcode. If executed, transaction is invalid. // public static let OP_2DIV: OpCodeProtocol = Op2Div() // Disabled opcode. If executed, transaction is invalid. // public static let OP_NEGATE: OpCodeProtocol = OpNegate() // negates the number, pops it from stack and pushes result. // public static let OP_ABS: OpCodeProtocol = OpAbsolute() // replaces number with its absolute value // public static let OP_NOT: OpCodeProtocol = OpNot() // replaces number with True if it's zero, False otherwise. // public static let OP_0NOTEQUAL: OpCodeProtocol = OP0NotEqual() // replaces number with True if it's not zero, False otherwise. // public static let OP_ADD: OpCodeProtocol = OpAdd() // (x y -- x+y) // public static let OP_SUB: OpCodeProtocol = OpSub() // (x y -- x-y) // public static let OP_MUL: OpCodeProtocol = OpMul() // Disabled opcode. If executed, transaction is invalid. // public static let OP_DIV: OpCodeProtocol = OpDiv() // Disabled opcode. If executed, transaction is invalid. // public static let OP_MOD: OpCodeProtocol = OpMod() // Disabled opcode. If executed, transaction is invalid. // public static let OP_LSHIFT: OpCodeProtocol = OpLShift() // Disabled opcode. If executed, transaction is invalid. // public static let OP_RSHIFT: OpCodeProtocol = OpRShift() // Disabled opcode. If executed, transaction is invalid. // // public static let OP_BOOLAND: OpCodeProtocol = OpBoolAnd() // public static let OP_BOOLOR: OpCodeProtocol = OpBoolOr() // public static let OP_NUMEQUAL: OpCodeProtocol = OpNumEqual() // public static let OP_NUMEQUALVERIFY: OpCodeProtocol = OpNumEqualVerify() // public static let OP_NUMNOTEQUAL: OpCodeProtocol = OpNumNotEqual() // public static let OP_LESSTHAN: OpCodeProtocol = OpLessThan() // public static let OP_GREATERTHAN: OpCodeProtocol = OpGreaterThan() // public static let OP_LESSTHANOREQUAL: OpCodeProtocol = OpLessThanOrEqual() // public static let OP_GREATERTHANOREQUAL: OpCodeProtocol = OpGreaterThanOrEqual() // public static let OP_MIN: OpCodeProtocol = OpMin() // public static let OP_MAX: OpCodeProtocol = OpMax() // // public static let OP_WITHIN: OpCodeProtocol = OpWithin() // // // Crypto // public static let OP_RIPEMD160: OpCodeProtocol = OpExample() // public static let OP_SHA1: OpCodeProtocol = OpExample() // public static let OP_SHA256: OpCodeProtocol = OpExample() // public static let OP_HASH160: OpCodeProtocol = OpHash160() // public static let OP_HASH256: OpCodeProtocol = OpExample() // public static let OP_CODESEPARATOR: OpCodeProtocol = OpExample() // This opcode is rarely used because it's useless, but we need to support it anyway. // public static let OP_CHECKSIG: OpCodeProtocol = OpCheckSig() // public static let OP_CHECKSIGVERIFY: OpCodeProtocol = OpCheckSigVerify() // public static let OP_CHECKMULTISIG: OpCodeProtocol = OpCheckMultiSig() // public static let OP_CHECKMULTISIGVERIFY: OpCodeProtocol = OpCheckMultiSigVerify() // // // Expansion // public static let OP_NOP1: OpCodeProtocol = OpExample() // public static let OP_NOP2: OpCodeProtocol = OpExample() // public static let OP_NOP3: OpCodeProtocol = OpExample() // public static let OP_NOP4: OpCodeProtocol = OpExample() // public static let OP_NOP5: OpCodeProtocol = OpExample() // public static let OP_NOP6: OpCodeProtocol = OpExample() // public static let OP_NOP7: OpCodeProtocol = OpExample() // public static let OP_NOP8: OpCodeProtocol = OpExample() // public static let OP_NOP9: OpCodeProtocol = OpExample() // public static let OP_NOP10: OpCodeProtocol = OpExample() // // public static let OP_INVALIDOPCODE: OpCodeProtocol = OpInvalidOpCode() // // internal static let list: [OpCodeProtocol] = [ // OP_0, // OP_FALSE, // OP_PUSHDATA1, // OP_PUSHDATA2, // OP_PUSHDATA4, // OP_1NEGATE, // OP_RESERVED, // OP_1, // OP_TRUE, // OP_2, // OP_3, // OP_4, // OP_5, // OP_6, // OP_7, // OP_8, // OP_9, // OP_10, // OP_11, // OP_12, // OP_13, // OP_14, // OP_15, // OP_16, // OP_NOP, // OP_VER, // OP_IF, // OP_NOTIF, // OP_VERIF, // OP_VERNOTIF, // OP_ELSE, // OP_ENDIF, // OP_VERIFY, // OP_RETURN, // OP_TOALTSTACK, // OP_FROMALTSTACK, // OP_2DROP, // OP_2DUP, // OP_3DUP, // OP_2OVER, // OP_2ROT, // OP_2SWAP, // OP_IFDUP, // OP_DEPTH, // OP_DROP, // OP_DUP, // OP_NIP, // OP_OVER, // OP_PICK, // OP_ROLL, // OP_ROT, // OP_SWAP, // OP_TUCK, // OP_CAT, // OP_SUBSTR, // OP_LEFT, // OP_RIGHT, // OP_SIZE, // OP_INVERT, // OP_AND, // OP_OR, // OP_XOR, // OP_EQUAL, // OP_EQUALVERIFY, // OP_RESERVED1, // OP_RESERVED2, // OP_1ADD, // OP_1SUB, // OP_2MUL, // OP_2DIV, // OP_NEGATE, // OP_ABS, // OP_NOT, // OP_0NOTEQUAL, // OP_ADD, // OP_SUB, // OP_MUL, // OP_DIV, // OP_MOD, // OP_LSHIFT, // OP_RSHIFT, // OP_BOOLAND, // OP_BOOLOR, // OP_NUMEQUAL, // OP_NUMEQUALVERIFY, // OP_NUMNOTEQUAL, // OP_LESSTHAN, // OP_GREATERTHAN, // OP_LESSTHANOREQUAL, // OP_GREATERTHANOREQUAL, // OP_MIN, // OP_MAX, // OP_WITHIN, // OP_RIPEMD160, // OP_SHA1, // OP_SHA256, // OP_HASH160, // OP_HASH256, // OP_CODESEPARATOR, // OP_CHECKSIG, // OP_CHECKSIGVERIFY, // OP_CHECKMULTISIG, // OP_CHECKMULTISIGVERIFY, // OP_NOP1, // OP_NOP2, // OP_NOP3, // OP_NOP4, // OP_NOP5, // OP_NOP6, // OP_NOP7, // OP_NOP8, // OP_NOP9, // OP_NOP10, // OP_INVALIDOPCODE // ] // // internal init() {} //} ================================================ FILE: HDWalletKit/Core/BitcoinScript/Script.swift ================================================ // // Script.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation import CryptoSwift public class Script { // An array of Data objects (pushing data) or UInt8 objects (containing opcodes) private var chunks: [ScriptChunk] // Cached serialized representations for -data and -string methods. private var dataCache: Data? private var stringCache: String? public var data: Data { // When we calculate data from scratch, it's important to respect actual offsets in the chunks as they may have been copied or shifted in subScript* methods. if let cache = dataCache { return cache } dataCache = chunks.reduce(Data()) { $0 + $1.chunkData } return dataCache! } public var string: String { if let cache = stringCache { return cache } stringCache = chunks.map { $0.string }.joined(separator: " ") return stringCache! } public var hex: String { return data.hex } public func toP2SH() -> Script { return try! Script() .append(.OP_HASH160) .appendData(RIPEMD160.hash(data.sha256())) .append(.OP_EQUAL) } // Multisignature script attribute. // If multisig script is not detected, this is nil public typealias MultisigVariables = (nSigRequired: UInt, publickeys: [PublicKey]) public var multisigRequirements: MultisigVariables? public init() { self.chunks = [ScriptChunk]() } public init(chunks: [ScriptChunk]) { self.chunks = chunks } public convenience init?(data: Data) { // It's important to keep around original data to correctly identify the size of the script for BTC_MAX_SCRIPT_SIZE check // and to correctly calculate hash for the signature because in BitcoinQT scripts are not re-serialized/canonicalized. do { let chunks = try Script.parseData(data) self.init(chunks: chunks) } catch let error { print(error) return nil } } public convenience init(hex: String) { self.init(data: Data(hex: hex))! } public convenience init?(address: Address) { self.init() switch address.type { case .pubkeyHash: // OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG do { try self.append(.OP_DUP) .append(.OP_HASH160) .appendData(address.data) .append(.OP_EQUALVERIFY) .append(.OP_CHECKSIG) } catch { return nil } case .scriptHash: // OP_HASH160 OP_EQUAL do { try self.append(.OP_HASH160) .appendData(address.data) .append(.OP_EQUAL) } catch { return nil } default: return nil } } // OP_ ... OP_ OP_CHECKMULTISIG public convenience init?(publicKeys: [PublicKey], signaturesRequired: UInt) { // First make sure the arguments make sense. // We need at least one signature guard signaturesRequired > 0 else { return nil } // And we cannot have more signatures than available pubkeys. guard publicKeys.count >= signaturesRequired else { return nil } // Both M and N should map to OP_<1..16> let mOpcode: OpCode = OpCodeFactory.opcode(for: Int(signaturesRequired)) let nOpcode: OpCode = OpCodeFactory.opcode(for: publicKeys.count) guard mOpcode != .OP_INVALIDOPCODE else { return nil } guard nOpcode != .OP_INVALIDOPCODE else { return nil } do { self.init() try append(mOpcode) for pubkey in publicKeys { try appendData(pubkey.data) } try append(nOpcode) try append(.OP_CHECKMULTISIG) multisigRequirements = (signaturesRequired, publicKeys) } catch { return nil } } private static func parseData(_ data: Data) throws -> [ScriptChunk] { guard !data.isEmpty else { return [ScriptChunk]() } var chunks = [ScriptChunk]() var i: Int = 0 let count: Int = data.count while i < count { // Exit if failed to parse let chunk = try ScriptChunkHelper.parseChunk(from: data, offset: i) chunks.append(chunk) i += chunk.range.count } return chunks } public var isStandard: Bool { return isPayToPublicKeyHashScript || isPayToScriptHashScript || isPublicKeyScript || isStandardMultisignatureScript } public var isPublicKeyScript: Bool { guard chunks.count == 2 else { return false } guard let pushdata = pushedData(at: 0) else { return false } return pushdata.count > 1 && opcode(at: 1) == OpCode.OP_CHECKSIG } public var isPayToPublicKeyHashScript: Bool { guard chunks.count == 5 else { return false } guard let dataChunk = chunk(at: 2) as? DataChunk else { return false } return opcode(at: 0) == OpCode.OP_DUP && opcode(at: 1) == OpCode.OP_HASH160 && dataChunk.range.count == 21 && opcode(at: 3) == OpCode.OP_EQUALVERIFY && opcode(at: 4) == OpCode.OP_CHECKSIG } public var isPayToScriptHashScript: Bool { guard chunks.count == 3 else { return false } return opcode(at: 0) == OpCode.OP_HASH160 && pushedData(at: 1)?.count == 20 // this is enough to match the exact byte template, any other encoding will be larger. && opcode(at: 2) == OpCode.OP_EQUAL } // Returns true if the script ends with P2SH check. // Not used in CoreBitcoin. Similar code is used in bitcoin-ruby. I don't know if we'll ever need it. public var endsWithPayToScriptHash: Bool { guard chunks.count >= 3 else { return false } return opcode(at: -3) == OpCode.OP_HASH160 && pushedData(at: -2)?.count == 20 && opcode(at: -1) == OpCode.OP_EQUAL } public var isStandardMultisignatureScript: Bool { guard isMultisignatureScript else { return false } guard let multisigPublicKeys = multisigRequirements?.publickeys else { return false } return multisigPublicKeys.count <= 3 } public var isMultisignatureScript: Bool { guard let requirements = multisigRequirements else { return false } if requirements.nSigRequired == 0 { detectMultisigScript() } return requirements.nSigRequired > 0 } public var isStandardOpReturnScript: Bool { guard chunks.count == 2 else { return false } return opcode(at: 0) == .OP_RETURN && pushedData(at: 1) != nil } public func standardOpReturnData() -> Data? { guard isStandardOpReturnScript else { return nil } return pushedData(at: 1) } // If typical multisig tx is detected, sets requirements: private func detectMultisigScript() { // multisig script must have at least 4 ops ("OP_1 OP_1 OP_CHECKMULTISIG") guard chunks.count >= 4 else { return } // The last op is multisig check. guard opcode(at: -1) == OpCode.OP_CHECKMULTISIG else { return } let mOpcode: OpCode = opcode(at: 0) let nOpcode: OpCode = opcode(at: -2) let m: Int = OpCodeFactory.smallInteger(from: mOpcode) let n: Int = OpCodeFactory.smallInteger(from: nOpcode) guard m > 0 && m != Int.max else { return } guard n > 0 && n != Int.max && n >= m else { return } // We must have correct number of pubkeys in the script. 3 extra ops: OP_, OP_ and OP_CHECKMULTISIG guard chunks.count == 3 + n else { return } var pubkeys: [PublicKey] = [] for i in 0...n { guard let data = pushedData(at: i) else { return } // TODO: Other coins let pubkey = PublicKey(privateKey: data, coin: .bitcoin) pubkeys.append(pubkey) } // Now we extracted all pubkeys and verified the numbers. multisigRequirements = (UInt(m), pubkeys) } // Include both PUSHDATA ops and OP_0..OP_16 literals. public var isDataOnly: Bool { return !chunks.contains { $0.opcodeValue > OpCode.OP_16 } } public var scriptChunks: [ScriptChunk] { return chunks } // MARK: - Modification public func invalidateSerialization() { dataCache = nil stringCache = nil multisigRequirements = nil } private func update(with updatedData: Data) throws { let updatedChunks = try Script.parseData(updatedData) chunks = updatedChunks invalidateSerialization() } @discardableResult public func append(_ opcode: OpCode) throws -> Script { let invalidOpCodes: [OpCode] = [.OP_PUSHDATA1, .OP_PUSHDATA2, .OP_PUSHDATA4, .OP_INVALIDOPCODE] guard !invalidOpCodes.contains(where: { $0 == opcode }) else { throw ScriptError.error("\(opcode.name) cannot be executed alone.") } var updatedData: Data = data updatedData += opcode try update(with: updatedData) return self } @discardableResult public func appendData(_ newData: Data) throws -> Script { guard !newData.isEmpty else { throw ScriptError.error("Data is empty.") } guard let addedScriptData = ScriptChunkHelper.scriptData(for: newData, preferredLengthEncoding: -1) else { throw ScriptError.error("Parse data to pushdata failed.") } var updatedData: Data = data updatedData += addedScriptData try update(with: updatedData) return self } @discardableResult public func appendScript(_ otherScript: Script) throws -> Script { guard !otherScript.data.isEmpty else { throw ScriptError.error("Script is empty.") } var updatedData: Data = self.data updatedData += otherScript.data try update(with: updatedData) return self } @discardableResult public func deleteOccurrences(of data: Data) throws -> Script { guard !data.isEmpty else { return self } let updatedData = chunks.filter { ($0 as? DataChunk)?.pushedData != data }.reduce(Data()) { $0 + $1.chunkData } try update(with: updatedData) return self } @discardableResult public func deleteOccurrences(of opcode: OpCode) throws -> Script { let updatedData = chunks.filter { $0.opCode != opcode }.reduce(Data()) { $0 + $1.chunkData } try update(with: updatedData) return self } public func subScript(from index: Int) throws -> Script { let subScript: Script = Script() for chunk in chunks[index.. Script { let subScript: Script = Script() for chunk in chunks[0.. ScriptChunk { return chunks[index < 0 ? chunks.count + index : index] } // Returns an opcode in a chunk. // If the chunk is data, not an opcode, returns OP_INVALIDOPCODE // Raises exception if index is out of bounds. public func opcode(at index: Int) -> OpCode { let chunk = self.chunk(at: index) // If the chunk is not actually an opcode, return invalid opcode. guard chunk is OpcodeChunk else { return .OP_INVALIDOPCODE } return chunk.opCode } // Returns Data in a chunk. // If chunk is actually an opcode, returns nil. // Raises exception if index is out of bounds. public func pushedData(at index: Int) -> Data? { let chunk = self.chunk(at: index) return (chunk as? DataChunk)?.pushedData } public func execute(with context: ScriptExecutionContext) throws { for chunk in chunks { if let opChunk = chunk as? OpcodeChunk { try opChunk.opCode.execute(context) } else if let dataChunk = chunk as? DataChunk { if context.shouldExecute { try context.pushToStack(dataChunk.pushedData) } } else { throw ScriptMachineError.error("Unknown chunk") } } guard context.conditionStack.isEmpty else { throw ScriptMachineError.error("Condition branches not balanced.") } } } extension Script { // Standard Transaction to Bitcoin address (pay-to-pubkey-hash) // scriptPubKey: OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG public static func buildPublicKeyHashOut(pubKeyHash: Data) -> Data { let values: [[UInt8]] = [ [OpCode.OP_DUP.value, OpCode.OP_HASH160.value, UInt8(pubKeyHash.count)], pubKeyHash.bytes, [OpCode.OP_EQUALVERIFY.value, OpCode.OP_CHECKSIG.value] ] return Data(values.reduce([], +)) } public static func buildPublicKeyUnlockingScript(signature: Data, pubkey: PublicKey, hashType: SighashType) -> Data { var data: Data = Data([UInt8(signature.count + 1)]) + signature + UInt8(hashType) data += VarInt(pubkey.data.count).serialized() data += pubkey.data return data } public static func isPublicKeyHashOut(_ script: Data) -> Bool { return script.count == 25 && script[0] == OpCode.OP_DUP && script[1] == OpCode.OP_HASH160 && script[2] == 20 && script[23] == OpCode.OP_EQUALVERIFY && script[24] == OpCode.OP_CHECKSIG } public static func getPublicKeyHash(from script: Data) -> Data { return script[3..<23] } } extension Script: CustomStringConvertible { public var description: String { return string } } enum ScriptError: Error { case error(String) } ================================================ FILE: HDWalletKit/Core/BitcoinScript/ScriptChunk.swift ================================================ // // ScriptChunk.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public protocol ScriptChunk { // Reference to the whole script binary data. var scriptData: Data { get } // A range of scriptData represented by this chunk. var range: Range { get } // Portion of scriptData defined by range. var chunkData: Data { get } // OP_CODE of scriptData defined by range. var opCode: OpCode { get } // String representation of a chunk. var string: String { get } // OP_1NEGATE, OP_0, OP_1..OP_16 are represented as a decimal number. // Most compactly represented pushdata chunks >=128 bit are encoded as // Smaller most compactly represented data is encoded as [] // Non-compact pushdata (e.g. 75-byte string with PUSHDATA1) contains a decimal prefix denoting a length size before hex data in square brackets. Ex. "1:[...]", "2:[...]" or "4:[...]" // For both compat and non-compact pushdata chunks, if the data consists of all printable characters (0x20..0x7E), it is enclosed not in square brackets, but in single quotes as characters themselves. Non-compact string is prefixed with 1:, 2: or 4: like described above. // Some other guys (BitcoinQT, bitcoin-ruby) encode "small enough" integers in decimal numbers and do that differently. // BitcoinQT encodes any data less than 4 bytes as a decimal number. // bitcoin-ruby encodes 2..16 as decimals, 0 and -1 as opcode names and the rest is in hex. // Now no matter which encoding you use, it can be parsed incorrectly. // Also: pushdata operations are typically encoded in a raw data which can be encoded in binary differently. // This means, you'll never be able to parse a sane-looking script into only one binary. // So forget about relying on parsing this thing exactly. Typically, we either have very small numbers (0..16), // or very big numbers (hashes and pubkeys). } extension ScriptChunk { public var opCode: OpCode { return OpCodeFactory.get(with: opcodeValue) } public var opcodeValue: UInt8 { return UInt8(scriptData[range.lowerBound]) } public var chunkData: Data { return scriptData.subdata(in: range) } public func updated(scriptData data: Data) -> ScriptChunk { if self is DataChunk { return DataChunk(scriptData: data, range: range) } else { return OpcodeChunk(scriptData: data, range: range) } } public func updated(scriptData data: Data, range updatedRange: Range) -> ScriptChunk { if self is DataChunk { return DataChunk(scriptData: data, range: updatedRange) } else { return OpcodeChunk(scriptData: data, range: updatedRange) } } } public struct OpcodeChunk: ScriptChunk { public var scriptData: Data public var range: Range public init(scriptData: Data, range: Range) { self.scriptData = scriptData self.range = range } public var string: String { return opCode.name } } public struct DataChunk: ScriptChunk { public var scriptData: Data public var range: Range public init(scriptData: Data, range: Range) { self.scriptData = scriptData self.range = range } public var pushedData: Data { return data } private var data: Data { var loc: Int = 1 if opCode == OpCode.OP_PUSHDATA1 { loc += 1 } else if opCode == OpCode.OP_PUSHDATA2 { loc += 2 } else if opCode == OpCode.OP_PUSHDATA4 { loc += 4 } return scriptData.subdata(in: (range.lowerBound + loc)..<(range.upperBound)) } public var string: String { var string: String guard !data.isEmpty else { return "OP_0" // Empty data is encoded as OP_0. } if isASCIIData(data: data) { string = String(data: data, encoding: String.Encoding.ascii)! // Escape escapes & single quote characters. string = string.replacingOccurrences(of: "\\", with: "\\\\") string = string.replacingOccurrences(of: "'", with: "\\'") // Wrap in single quotes. Why not double? Because they are already used in JSON and we don't want to multiply the mess. string = "'" + string + "'" } else { string = data.hex // Shorter than 128-bit chunks are wrapped in square brackets to avoid ambiguity with big all-decimal numbers. if data.count < 16 { string = "[\(string)]" } } // Non-compact data is prefixed with an appropriate length prefix. if !isDataCompact { var prefix = 1 if opCode == OpCode.OP_PUSHDATA2 { prefix = 2 } else if opCode == OpCode.OP_PUSHDATA4 { prefix = 4 } string = String(prefix) + ":" + string } return string } // Returns true if the data is represented with the most compact opcode. public var isDataCompact: Bool { switch opCode.value { case ...OpCode.OP_PUSHDATA1.value: return true // length fits in one byte under OP_PUSHDATA1. case OpCode.OP_PUSHDATA1.value: return data.count >= OpCode.OP_PUSHDATA1.value // length should not be less than OP_PUSHDATA1 case OpCode.OP_PUSHDATA2.value: return data.count > (0xff) // length should not fit in one byte case OpCode.OP_PUSHDATA4.value: return data.count > (0xffff) // length should not fit in two bytes default: return false } } private func isASCIIData(data: Data) -> Bool { for ch in data { if !(ch >= 0x20 && ch <= 0x7E) { return false } } return true } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/ScriptChunkHelper.swift ================================================ // // ScriptChunkHelper.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public enum ScriptChunkError: Error { case error(String) } public struct ScriptChunkHelper { // If encoding is -1, then the most compact will be chosen. // Valid values: -1, 0, 1, 2, 4. // Returns nil if preferredLengthEncoding can't be used for data, or data is nil or too big. public static func scriptData(for data: Data, preferredLengthEncoding: Int) -> Data? { var scriptData: Data = Data() if data.count < OpCode.OP_PUSHDATA1 && preferredLengthEncoding <= 0 { // do nothing scriptData += UInt8(data.count) } else if data.count <= (0xff) && (preferredLengthEncoding == -1 || preferredLengthEncoding == 1) { scriptData += OpCode.OP_PUSHDATA1 scriptData += UInt8(data.count) } else if data.count <= (0xffff) && (preferredLengthEncoding == -1 || preferredLengthEncoding == 2) { scriptData += OpCode.OP_PUSHDATA2 scriptData += UInt16(data.count) } else if UInt64(data.count) <= 0xffffffff && (preferredLengthEncoding == -1 || preferredLengthEncoding == 4) { scriptData += OpCode.OP_PUSHDATA4 scriptData += UInt64(data.count) } else { // Invalid preferredLength encoding or data size is too big. return nil } scriptData += data return scriptData } public static func parseChunk(from scriptData: Data, offset: Int) throws -> ScriptChunk { // Data should fit at least one opcode. guard scriptData.count > offset else { throw ScriptChunkError.error("Parse ScriptChunk failed. Offset is out of range.") } let opcode: UInt8 = scriptData[offset] if opcode > OpCode.OP_PUSHDATA4 { // simple opcode let range = offset.. DataChunk { // for range let count: Int = scriptData.count let chunkLength: Int switch opcode { case 0.. Void in guard let baseAddress = pointer.baseAddress else { return } memcpy(&dataLength, baseAddress + offset + MemoryLayout.size(ofValue: opcode), MemoryLayout.size(ofValue: dataLength)) }) chunkLength = MemoryLayout.size(ofValue: opcode) + MemoryLayout.size(ofValue: dataLength) + Int(dataLength) case OpCode.OP_PUSHDATA2.value: var dataLength = UInt16() guard offset + MemoryLayout.size(ofValue: dataLength) <= count else { throw ScriptChunkError.error("Parse DataChunk failed. OP_PUSHDATA2 error") } _ = scriptData.withUnsafeBytes({ (pointer) -> Void in guard let baseAddress = pointer.baseAddress else { return } memcpy(&dataLength, baseAddress + offset + MemoryLayout.size(ofValue: opcode), MemoryLayout.size(ofValue: dataLength)) }) dataLength = CFSwapInt16LittleToHost(dataLength) chunkLength = MemoryLayout.size(ofValue: opcode) + MemoryLayout.size(ofValue: dataLength) + Int(dataLength) case OpCode.OP_PUSHDATA4.value: var dataLength = UInt32() guard offset + MemoryLayout.size(ofValue: dataLength) <= count else { throw ScriptChunkError.error("Parse DataChunk failed. OP_PUSHDATA4 error") } _ = scriptData.withUnsafeBytes({ (pointer) -> Void in guard let baseAddress = pointer.baseAddress else { return } memcpy(&dataLength, baseAddress + offset + MemoryLayout.size(ofValue: opcode), MemoryLayout.size(ofValue: dataLength)) }) dataLength = CFSwapInt32LittleToHost(dataLength) // CoreBitcoin uses CFSwapInt16LittleToHost(dataLength) chunkLength = MemoryLayout.size(ofValue: opcode) + MemoryLayout.size(ofValue: dataLength) + Int(dataLength) default: // cannot happen because it's opcode throw ScriptChunkError.error("Parse DataChunk failed. OP_CODE: \(opcode).") } guard offset + chunkLength <= count else { throw ScriptChunkError.error("Parse DataChunk failed. Push data is out of bounds error.") } let range: Range = offset.. inputIndex else { return nil } self.transaction = transaction self.utxoToVerify = utxoToVerify self.txinToVerify = transaction.inputs[Int(inputIndex)] self.inputIndex = inputIndex } public var shouldExecute: Bool { return !conditionStack.contains(false) } public func shouldVerifyP2SH() -> Bool { return blockTimeStamp >= BTC_BIP16_TIMESTAMP } private func normalized(_ index: Int) -> Int { return (index < 0) ? stack.count + index : index } // stack public func pushToStack(_ bool: Bool) { stack.append(bool ? blobTrue : blobFalse) } public func pushToStack(_ n: Int32) throws { stack.append(BigNumber(n.littleEndian).data) } public func pushToStack(_ data: Data) throws { guard data.count <= BTC_MAX_SCRIPT_ELEMENT_SIZE else { throw ScriptMachineError.error("PushedData size is too big.") } stack.append(data) } public func resetStack() { stack = [] altStack = [] conditionStack = [] } public func swapDataAt(i: Int, j: Int) { stack.swapAt(normalized(i), normalized(j)) } public func assertStackHeightGreaterThanOrEqual(_ n: Int) throws { guard stack.count >= n else { throw OpCodeExecutionError.opcodeRequiresItemsOnStack(n) } } public func assertAltStackHeightGreaterThanOrEqual(_ n: Int) throws { guard altStack.count >= n else { throw OpCodeExecutionError.error("Operation requires \(n) items on altstack.") } } // OpCount public func incrementOpCount(by i: Int = 1) throws { opCount += i guard opCount <= BTC_MAX_OPS_PER_SCRIPT else { throw OpCodeExecutionError.error("Exceeded the allowed number of operations per script.") } } public func deserializeP2SHLockScript(stackForP2SH: [Data]) throws -> Script { var stackForP2SH: [Data] = stackForP2SH // Instantiate the script from the last data on the stack. guard let last = stackForP2SH.last, let deserializedLockScript = Script(data: last) else { // stackForP2SH cannot be empty here, because if it was the // P2SH HASH <> EQUAL scriptPubKey would be evaluated with // an empty stack and the runScript: above would return NO. throw ScriptMachineError.exception("internal inconsistency: stackForP2SH cannot be empty at this point.") } // Remove it from the stack. stackForP2SH.removeLast() // Replace current stack with P2SH stack. resetStack() stack = stackForP2SH return deserializedLockScript } public func data(at i: Int) -> Data { return stack[normalized(i)] } public func number(at i: Int) throws -> Int32 { let data: Data = stack[normalized(i)] guard data.count <= 4 else { throw OpCodeExecutionError.invalidBignum } return BigNumber(data).int32 } public func bool(at i: Int) -> Bool { let data: Data = stack[normalized(i)] guard !data.isEmpty else { return false } for (i, byte) in data.enumerated() where byte != 0 { // Can be negative zero, also counts as false if i == (data.count - 1) && byte == 0x80 { return false } return true } return false } } extension ScriptExecutionContext: CustomStringConvertible { public var description: String { var desc: String = "" for data in stack.reversed() { let hex = data.hex var contents: String = "0x" + hex if hex.count > 20 { let first = hex.prefix(5) let last = hex.suffix(5) contents = "\(first)..\(last) [\(data.count)bytes]" } if contents == "0x" { contents = "NULL [FALSE/0]" } if contents == "0x01" { contents = "0x01 [TRUE/1]" } for _ in 0...(24 - contents.count) / 2 { contents = " \(contents) " } desc += "| \(contents) |\n" } var base: String = "" (0...14).forEach { _ in base = "=\(base)=" } return desc + base + "\n" } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/ScriptFactory.swift ================================================ // // ScriptFactory.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public struct ScriptFactory { // Basic public struct Standard {} public struct LockTime {} public struct MultiSig {} public struct OpReturn {} public struct Condition {} // Contract public struct HashedTimeLockedContract {} } // MARK: - Standard public extension ScriptFactory.Standard { static func buildP2PK(publickey: PublicKey) -> Script? { return try? Script() .appendData(publickey.data) .append(.OP_CHECKSIG) } static func buildP2PKH(address: Address) -> Script? { return Script(address: address) } static func buildP2SH(script: Script) -> Script { return script.toP2SH() } static func buildMultiSig(publicKeys: [PublicKey]) -> Script? { return Script(publicKeys: publicKeys, signaturesRequired: UInt(publicKeys.count)) } static func buildMultiSig(publicKeys: [PublicKey], signaturesRequired: UInt) -> Script? { return Script(publicKeys: publicKeys, signaturesRequired: signaturesRequired) } } // MARK: - LockTime public extension ScriptFactory.LockTime { // Base static func build(script: Script, lockDate: Date) -> Script? { return try? Script() .appendData(lockDate.bigNumData) .append(.OP_CHECKLOCKTIMEVERIFY) .append(.OP_DROP) .appendScript(script) } static func build(script: Script, lockIntervalSinceNow: TimeInterval) -> Script? { let lockDate = Date(timeIntervalSinceNow: lockIntervalSinceNow) return build(script: script, lockDate: lockDate) } // P2PKH + LockTime static func build(address: Address, lockIntervalSinceNow: TimeInterval) -> Script? { guard let p2pkh = Script(address: address) else { return nil } let lockDate = Date(timeIntervalSinceNow: lockIntervalSinceNow) return build(script: p2pkh, lockDate: lockDate) } static func build(address: Address, lockDate: Date) -> Script? { guard let p2pkh = Script(address: address) else { return nil } return build(script: p2pkh, lockDate: lockDate) } } // MARK: - OpReturn public extension ScriptFactory.OpReturn { static func build(text: String) -> Script? { let MAX_OP_RETURN_DATA_SIZE: Int = 220 guard let data = text.data(using: .utf8), data.count <= MAX_OP_RETURN_DATA_SIZE else { return nil } return try? Script() .append(.OP_RETURN) .appendData(data) } } // MARK: - Condition public extension ScriptFactory.Condition { static func build(scripts: [Script]) -> Script? { guard !scripts.isEmpty else { return nil } guard scripts.count > 1 else { return scripts[0] } var scripts: [Script] = scripts while scripts.count > 1 { var newScripts: [Script] = [] while !scripts.isEmpty { let script = Script() do { if scripts.count == 1 { try script .append(.OP_DROP) .appendScript(scripts.removeFirst()) } else { try script .append(.OP_IF) .appendScript(scripts.removeFirst()) .append(.OP_ELSE) .appendScript(scripts.removeFirst()) .append(.OP_ENDIF) } } catch { return nil } newScripts.append(script) } scripts = newScripts } return scripts[0] } } // MARK: - HTLC /* OP_IF [HASHOP] OP_EQUALVERIFY OP_DUP OP_HASH160 OP_ELSE [TIMEOUTOP] OP_DROP OP_DUP OP_HASH160 OP_ENDIF OP_EQUALVERIFYs OP_CHECKSIG */ public extension ScriptFactory.HashedTimeLockedContract { // Base static func build(recipient: Address, sender: Address, lockDate: Date, hash: Data, hashOp: HashOperator) -> Script? { guard hash.count == hashOp.hashSize else { return nil } return try? Script() .append(.OP_IF) .append(hashOp.opcode) .appendData(hash) .append(.OP_EQUALVERIFY) .append(.OP_DUP) .append(.OP_HASH160) .appendData(recipient.data) .append(.OP_ELSE) .appendData(lockDate.bigNumData) .append(.OP_CHECKLOCKTIMEVERIFY) .append(.OP_DROP) .append(.OP_DUP) .append(.OP_HASH160) .appendData(sender.data) .append(.OP_ENDIF) .append(.OP_EQUALVERIFY) .append(.OP_CHECKSIG) } // convenience static func build(recipient: Address, sender: Address, lockIntervalSinceNow: TimeInterval, hash: Data, hashOp: HashOperator) -> Script? { let lockDate = Date(timeIntervalSinceNow: lockIntervalSinceNow) return build(recipient: recipient, sender: sender, lockDate: lockDate, hash: hash, hashOp: hashOp) } static func build(recipient: Address, sender: Address, lockIntervalSinceNow: TimeInterval, secret: Data, hashOp: HashOperator) -> Script? { let hash = hashOp.hash(secret) let lockDate = Date(timeIntervalSinceNow: lockIntervalSinceNow) return build(recipient: recipient, sender: sender, lockDate: lockDate, hash: hash, hashOp: hashOp) } static func build(recipient: Address, sender: Address, lockDate: Date, secret: Data, hashOp: HashOperator) -> Script? { let hash = hashOp.hash(secret) return build(recipient: recipient, sender: sender, lockDate: lockDate, hash: hash, hashOp: hashOp) } } public class HashOperator { public static let SHA256: HashOperator = HashOperatorSha256() public static let HASH160: HashOperator = HashOperatorHash160() public var opcode: OpCode { return .OP_INVALIDOPCODE } public var hashSize: Int { return 0 } public func hash(_ data: Data) -> Data { return Data() } fileprivate init() {} } final public class HashOperatorSha256: HashOperator { override public var opcode: OpCode { return .OP_SHA256 } override public var hashSize: Int { return 32 } override public func hash(_ data: Data) -> Data { return data.sha256() } } final public class HashOperatorHash160: HashOperator { override public var opcode: OpCode { return .OP_HASH160 } override public var hashSize: Int { return 20 } override public func hash(_ data: Data) -> Data { return RIPEMD160.hash(data.sha256()) } } // MARK: - Utility Extension private extension Date { var bigNumData: Data { let dateUnix: TimeInterval = timeIntervalSince1970 let bn = BigNumber(Int32(dateUnix).littleEndian) return bn.data } } ================================================ FILE: HDWalletKit/Core/BitcoinScript/ScriptMachine.swift ================================================ // // ScriptMachine.swift // // Copyright © 2018 BitcoinKit developers // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import Foundation public enum ScriptVerification { case StrictEncoding // enforce strict conformance to DER and SEC2 for signatures and pubkeys (aka SCRIPT_VERIFY_STRICTENC) case EvenS // enforce lower S values (below curve halforder) in signatures (aka SCRIPT_VERIFY_EVEN_S, depends on STRICTENC) } public enum ScriptMachineError: Error { case exception(String) case error(String) case opcodeRequiresItemsOnStack(Int) case invalidBignum } // ScriptMachine is a stack machine (like Forth) that evaluates a predicate // returning a bool indicating valid or not. There are no loops. // You can -copy a machine which will copy all the parameters and the stack state. public struct ScriptMachine { public init() { } public static func verifyTransaction(signedTx: Transaction, inputIndex: UInt32, utxo: TransactionOutput, blockTimeStamp: UInt32 = UInt32(NSTimeIntervalSince1970)) throws -> Bool { // Sanity check: transaction and its input should be consistent. guard inputIndex < signedTx.inputs.count else { throw ScriptMachineError.exception("Transaction and valid inputIndex are required for script verification.") } let context: ScriptExecutionContext = ScriptExecutionContext(transaction: signedTx, utxoToVerify: utxo, inputIndex: inputIndex)! context.blockTimeStamp = blockTimeStamp let txInput: TransactionInput = signedTx.inputs[Int(inputIndex)] guard let unlockScript = Script(data: txInput.signatureScript), let lockScript = Script(data: utxo.lockingScript) else { throw ScriptMachineError.error("Both lock script and sig script must be valid.") } return try verify(lockScript: lockScript, unlockScript: unlockScript, context: context) } public static func verify(lockScript: Script, unlockScript: Script, context: ScriptExecutionContext) throws -> Bool { // First step: run the input script which typically places signatures, pubkeys and other static data needed for outputScript. try run(unlockScript, context: context) // Make a copy of the stack if we have P2SH script. // We will run deserialized P2SH script on this stack. let stackForP2SH: [Data] = context.stack // Second step: run output script to see that the input satisfies all conditions laid in the output script. try run(lockScript, context: context) // We need to have something on stack guard !context.stack.isEmpty else { throw ScriptMachineError.error("Stack is empty after script execution.") } // The last value must be true. guard context.bool(at: -1) else { throw ScriptMachineError.error("Last item on the stack is false.") } // Additional validation for spend-to-script-hash transactions: if context.shouldVerifyP2SH() && lockScript.isPayToScriptHashScript { guard unlockScript.isDataOnly else { throw ScriptMachineError.error("Input script for P2SH spending must be literals-only.") } let deserializedLockScript = try context.deserializeP2SHLockScript(stackForP2SH: stackForP2SH) try run(deserializedLockScript, context: context) // We need to have something on stack guard !context.stack.isEmpty else { throw ScriptMachineError.error("Stack is empty after script execution.") } // The last value must be YES. guard context.bool(at: -1) else { throw ScriptMachineError.error("Last item on the stack is false.") } } else { if context.verbose { print("context.shouldVerifyP2SH : ", context.shouldVerifyP2SH(), "isP2SH : ", lockScript.isPayToScriptHashScript) } } // If nothing failed, validation passed. return true } public static func run(_ script: Script, context: ScriptExecutionContext) throws { guard script.data.count <= BTC_MAX_SCRIPT_SIZE else { throw ScriptMachineError.exception("Script binary is too long.") } // Altstack should be reset between script runs. try script.execute(with: context) } } private extension Array { subscript (normalized index: Int) -> Element { return (index < 0) ? self[count + index] : self[index] } } ================================================ FILE: HDWalletKit/Core/ByteStream.swift ================================================ // // ByteStream.swift // HDWalletKit // // Created by Pavlo Boiko on 1/6/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation class ByteStream { let data: Data private var offset = 0 var availableBytes: Int { return data.count - offset } init(_ data: Data) { self.data = data } func read(_ type: T.Type) -> T { let size = MemoryLayout.size let value = data[offset..<(offset + size)].to(type: type) offset += size return value } func read(_ type: VarInt.Type) -> VarInt { let len = data[offset..<(offset + 1)].to(type: UInt8.self) let length: UInt64 switch len { case 0...252: length = UInt64(len) offset += 1 case 0xfd: offset += 1 length = UInt64(data[offset..<(offset + 2)].to(type: UInt16.self)) offset += 2 case 0xfe: offset += 1 length = UInt64(data[offset..<(offset + 4)].to(type: UInt32.self)) offset += 4 case 0xff: offset += 1 length = UInt64(data[offset..<(offset + 8)].to(type: UInt64.self)) offset += 8 default: offset += 1 length = UInt64(data[offset..<(offset + 8)].to(type: UInt64.self)) offset += 8 } return VarInt(length) } func read(_ type: VarString.Type) -> VarString { let length = read(VarInt.self).underlyingValue let size = Int(length) let value = data[offset..<(offset + size)].to(type: String.self) offset += size return VarString(value) } func read(_ type: Data.Type, count: Int) -> Data { let value = data[offset..<(offset + count)] offset += count return Data(value) } } ================================================ FILE: HDWalletKit/Core/Converter/WeiEthterConverter.swift ================================================ // // WeiEthterConverter.swift // HDWalletKit // // Created by Pavlo Boiko on 10/10/18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public class WeiEthterConverter { // NOTE: calculate wei by 10^18 private static let etherInWei = pow(Decimal(10), 18) /// Convert Wei(BInt) unit to Ether(Decimal) unit public static func toEther(wei: Wei) throws -> Ether { guard let decimalWei = Decimal(string: wei.description) else { throw HDWalletKitError.convertError(.failedToConvert(wei.description)) } return decimalWei / etherInWei } /// Convert Ether(Decimal) unit to Wei(BInt) unit public static func toWei(ether: Ether) throws -> Wei { guard let wei = Wei((ether * etherInWei).description) else { throw HDWalletKitError.convertError(.failedToConvert(ether * etherInWei)) } return wei } /// Convert Ether(String) unit to Wei(BInt) unit public static func toWei(ether: String) throws -> Wei { guard let decimalEther = Decimal(string: ether) else { throw HDWalletKitError.convertError(.failedToConvert(ether)) } return try toWei(ether: decimalEther) } ///Convert Wei to Tokens balance public static func toToken(balance: String, decimals: Int, radix: Int) throws -> Ether { guard let wei = Wei(balance, radix: radix), let decimalWei = Decimal(string: wei.description) else { throw HDWalletKitError.convertError(.failedToConvert(balance)) } return decimalWei / pow(10, decimals) } // Only used for calcurating gas price and gas limit. public static func toWei(GWei: Int) -> Int { return GWei * 1000000000 } } ================================================ FILE: HDWalletKit/Core/Crypto/Encryption/Crypto.swift ================================================ // // Crypto.swift // WalletKit // // Created by yuzushioh on 2018/02/06. // Copyright © 2018 yuzushioh. All rights reserved. // import CryptoSwift public final class Crypto { public static func HMACSHA512(key: Data, data: Data) -> Data { let output: [UInt8] do { output = try HMAC(key: key.bytes, variant: .sha512).authenticate(data.bytes) } catch let error { fatalError("Error occured. Description: \(error.localizedDescription)") } return Data(output) } public static func PBKDF2SHA512(password: [UInt8], salt: [UInt8]) -> Data { let output: [UInt8] do { output = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 2048, variant: .sha512).calculate() } catch let error { fatalError("PKCS5.PBKDF2 faild: \(error.localizedDescription)") } return Data(output) } public static func generatePublicKey(data: Data, compressed: Bool) -> Data { let encrypter = EllipticCurveEncrypterSecp256k1() var publicKey = encrypter.createPublicKey(privateKey: data) return encrypter.export(publicKey: &publicKey, compressed: compressed) } public static func sha3keccak256(data:Data) -> Data { return Data(SHA3(variant: .keccak256).calculate(for: data.bytes)) } public static func hashSHA3_256(_ data: Data) -> Data { return Data(CryptoSwift.SHA3(variant: .sha256).calculate(for: data.bytes)) } public static func sign(_ hash: Data, privateKey: Data) throws -> Data { let encrypter = EllipticCurveEncrypterSecp256k1() guard var signatureInInternalFormat = encrypter.sign(hash: hash, privateKey: privateKey) else { throw HDWalletKitError.failedToSign } return encrypter.export(signature: &signatureInInternalFormat) } public static func verifySigData(for tx: Transaction, inputIndex: Int, utxo: TransactionOutput, sigData: Data, pubKeyData: Data) throws -> Bool { // Hash type is one byte tacked on to the end of the signature. So the signature shouldn't be empty. guard !sigData.isEmpty else { throw ScriptMachineError.error("SigData is empty.") } // Extract hash type from the last byte of the signature. let hashType = SighashType(sigData.last!) // Strip that last byte to have a pure signature. let signature = sigData.dropLast() let sighash: Data = tx.signatureHash(for: utxo, inputIndex: inputIndex, hashType: hashType) return try ECDSA.secp256k1.verifySignature(signature, message: sighash, publicKeyData: pubKeyData) } } // MARK: SHA256 of SHA256 extension Data { var doubleSHA256: Data { return sha256().sha256() } } ================================================ FILE: HDWalletKit/Core/Crypto/Encryption/ECDSA.swift ================================================ // // ECDSA.swift // ECDSA // // Created by yuzushioh on 2018/01/25. // Copyright © 2018 yuzushioh. All rights reserved. // import Foundation import secp256k1 public final class ECDSA { public static let secp256k1 = ECDSA() public static func sign(_ data: Data, privateKey: Data) throws -> Data { let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN))! defer { secp256k1_context_destroy(ctx) } let signature = UnsafeMutablePointer.allocate(capacity: 1) defer { signature.deallocate() } data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in guard let dataPointer = ptr.bindMemory(to: UInt8.self).baseAddress else { return } privateKey.withUnsafeBytes { (pkPtr: UnsafeRawBufferPointer) in guard let privateKeyPointer = pkPtr.bindMemory(to: UInt8.self).baseAddress else { return } secp256k1_ecdsa_sign(ctx, signature, dataPointer, privateKeyPointer, nil, nil) } } let normalizedsig = UnsafeMutablePointer.allocate(capacity: 1) defer { normalizedsig.deallocate() } secp256k1_ecdsa_signature_normalize(ctx, normalizedsig, signature) var length: size_t = 128 var der = Data(count: length) der.withUnsafeMutableBytes({ (ptr: UnsafeMutableRawBufferPointer) -> Void in guard let pointer = ptr.bindMemory(to: UInt8.self).baseAddress else { return } secp256k1_ecdsa_signature_serialize_der(ctx, pointer, &length, normalizedsig) }) der.count = length return der } public func verifySignature(_ sigData: Data, message: Data, publicKeyData: Data) throws -> Bool { guard let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_VERIFY)) else { return false } var pubkey = secp256k1_pubkey() var signature = secp256k1_ecdsa_signature() secp256k1_ecdsa_signature_parse_der(ctx, &signature, sigData.bytes, sigData.count) if (secp256k1_ec_pubkey_parse(ctx, &pubkey, publicKeyData.bytes, publicKeyData.count) != 1) { return false }; if (secp256k1_ecdsa_verify(ctx, &signature, message.bytes, &pubkey) != 1) { return false }; secp256k1_context_destroy(ctx); return true } } ================================================ FILE: HDWalletKit/Core/Crypto/Encryption/EIP155Signer.swift ================================================ import CryptoSwift public struct EIP155Signer { public init(chainId: Int) { self.chainId = chainId } private let chainId: Int public func sign(_ rawTransaction: EthereumRawTransaction, privateKey: PrivateKey) throws -> Data { let transactionHash = try hash(rawTransaction: rawTransaction) let signature = try privateKey.sign(hash: transactionHash) return try signTransaction(signature: signature, rawTransaction: rawTransaction) } public func sign(_ rawTransaction: EthereumRawTransaction, privateKey: Data) throws -> Data { let transactionHash = try hash(rawTransaction: rawTransaction) let signature = try Crypto.sign(transactionHash, privateKey: privateKey) return try signTransaction(signature: signature, rawTransaction: rawTransaction) } private func signTransaction(signature: Data, rawTransaction: EthereumRawTransaction) throws -> Data { let (r, s, v) = calculateRSV(signature: signature) return try RLP.encode([ rawTransaction.nonce, rawTransaction.gasPrice, rawTransaction.gasLimit, rawTransaction.to.data, rawTransaction.value, rawTransaction.data, v, r, s ]) } public func hash(rawTransaction: EthereumRawTransaction) throws -> Data { return Crypto.sha3keccak256(data: try encode(rawTransaction: rawTransaction)) } public func encode(rawTransaction: EthereumRawTransaction) throws -> Data { var toEncode: [Any] = [ rawTransaction.nonce, rawTransaction.gasPrice, rawTransaction.gasLimit, rawTransaction.to.data, rawTransaction.value, rawTransaction.data] if chainId != 0 { toEncode.append(contentsOf: [chainId, 0, 0 ]) // EIP155 } return try RLP.encode(toEncode) } public func calculateRSV(signature: Data) -> (r: BInt, s: BInt, v: BInt) { return ( r: BInt(str: signature[..<32].toHexString(), radix: 16)!, s: BInt(str: signature[32..<64].toHexString(), radix: 16)!, v: BInt(signature[64]) + (chainId == 0 ? 27 : (35 + 2 * chainId)) ) } public func calculateSignature(r: BInt, s: BInt, v: BInt) -> Data { let isOldSignitureScheme = [27, 28].contains(v) let suffix = isOldSignitureScheme ? v - 27 : v - 35 - 2 * chainId let sigHexStr = hex64Str(r) + hex64Str(s) + suffix.asString(withBase: 16) return Data(hex: sigHexStr) } private func hex64Str(_ i: BInt) -> String { let hex = i.asString(withBase: 16) return String(repeating: "0", count: 64 - hex.count) + hex } } ================================================ FILE: HDWalletKit/Core/Crypto/Encryption/EllipticCurveEncrypterSecp256k1.swift ================================================ // // EllipticCurveEncrypterSecp256k1.swift // HDWalletKit // // Created by Pavlo Boiko on 12.07.18. // Copyright © 2018 Essentia. All rights reserved. // import secp256k1 import CryptoSwift public class EllipticCurveEncrypterSecp256k1 { // holds internal state of the c library private let context: OpaquePointer public init() { context = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY))! } deinit { secp256k1_context_destroy(context) } /// Recovers public key from the PrivateKey. Use import(signature:) to convert signature from bytes. /// /// - Parameters: /// - privateKey: private key bytes /// - Returns: public key structure public func createPublicKey(privateKey: Data) -> secp256k1_pubkey { let privateKey = privateKey.bytes var publickKey = secp256k1_pubkey() _ = SecpResult(secp256k1_ec_pubkey_create(context, &publickKey, privateKey)) return publickKey } /// Signs the hash with the private key. Produces signature data structure that can be exported with /// export(signature:) method. /// /// - Parameters: /// - hash: 32-byte (256-bit) hash of the message /// - privateKey: 32-byte private key /// - Returns: signature data structure if signing succeeded, otherwise nil. public func sign(hash: Data, privateKey: Data) -> secp256k1_ecdsa_recoverable_signature? { precondition(hash.count == 32, "Hash must be 32 bytes size") var signature = secp256k1_ecdsa_recoverable_signature() privateKey.withUnsafeBytes { privateKey -> Void in guard let privateKeyPtr = privateKey.bindMemory(to: UInt8.self).baseAddress else { return } hash.withUnsafeBytes { hash -> Void in guard let hashPtr = hash.bindMemory(to: UInt8.self).baseAddress else { return } secp256k1_ecdsa_sign_recoverable(context, &signature, hashPtr, privateKeyPtr, nil, nil) } } return signature } /// Converts signature data structure to 65 bytes. /// /// - Parameter signature: signature data structure /// - Returns: 65 byte exported signature data. public func export(signature: inout secp256k1_ecdsa_recoverable_signature) -> Data { var output = Data(count: 65) var recId = 0 as Int32 _ = output.withUnsafeMutableBytes { output in guard let p = output.bindMemory(to: UInt8.self).baseAddress else { return } secp256k1_ecdsa_recoverable_signature_serialize_compact(context, p, &recId, &signature) } output[64] = UInt8(recId) return output } /// Converts serialized signature into library's signature format. Use it to supply signature to /// the publicKey(signature:hash:) method. /// /// - Parameter signature: serialized 65-byte signature /// - Returns: signature structure public func `import`(signature: Data) -> secp256k1_ecdsa_recoverable_signature { precondition(signature.count == 65, "Signature must be 65 byte size") var sig = secp256k1_ecdsa_recoverable_signature() let recId = Int32(signature[64]) signature.withUnsafeBytes { input -> Void in guard let p = input.bindMemory(to: UInt8.self).baseAddress else { return } secp256k1_ecdsa_recoverable_signature_parse_compact(context, &sig, p, recId) } return sig } /// Recovers public key from the signature and the hash. Use import(signature:) to convert signature from bytes. /// Use export(publicKey:compressed) to convert recovered public key into bytes. /// /// - Parameters: /// - signature: signature structure /// - hash: 32-byte (256-bit) hash of a message /// - Returns: public key structure or nil, if signature invalid public func publicKey(signature: inout secp256k1_ecdsa_recoverable_signature, hash: Data) -> secp256k1_pubkey? { precondition(hash.count == 32, "Hash must be 32 bytes size") let hash = hash.bytes var outPubKey = secp256k1_pubkey() let status = SecpResult(secp256k1_ecdsa_recover(context, &outPubKey, &signature, hash)) return status == .success ? outPubKey : nil } /// Converts public key from library's data structure to bytes /// /// - Parameters: /// - publicKey: public key structure to convert. /// - compressed: whether public key should be compressed. /// - Returns: If compression enabled, public key is 33 bytes size, otherwise it is 65 bytes. public func export(publicKey: inout secp256k1_pubkey, compressed: Bool) -> Data { var output = Data(count: compressed ? 33 : 65) var outputLen: Int = output.count let compressedFlags = compressed ? UInt32(SECP256K1_EC_COMPRESSED) : UInt32(SECP256K1_EC_UNCOMPRESSED) output.withUnsafeMutableBytes { pointer -> Void in guard let p = pointer.bindMemory(to: UInt8.self).baseAddress else { return } secp256k1_ec_pubkey_serialize(context, p, &outputLen, &publicKey, compressedFlags) } return output } } ================================================ FILE: HDWalletKit/Core/Crypto/Encryption/SecpResult.swift ================================================ // // SecpResult.swift // HDWalletKit // // Created by Pavlo Boiko on 13.07.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation enum SecpResult { case success case failure init(_ result:Int32) { switch result { case 1: self = .success default: self = .failure } } } ================================================ FILE: HDWalletKit/Core/Crypto/Hash/RIPEMD160.swift ================================================ // // RIPEMD160.swift // WalletKit // // Created by yuzushioh on 2018/02/04. // Copyright © 2018 yuzushioh. All rights reserved. // import Foundation struct RIPEMD160 { private var MDbuf: (UInt32, UInt32, UInt32, UInt32, UInt32) private var buffer: Data private var count: Int64 // Total # of bytes processed. private init() { MDbuf = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0) buffer = Data() count = 0 } private mutating func compress(_ X: UnsafePointer) { // *** Helper functions (originally macros in rmd160.h) *** /* ROL(x, n) cyclically rotates x over n bits to the left */ /* x must be of an unsigned 32 bits type and 0 <= n < 32. */ func ROL(_ x: UInt32, _ n: UInt32) -> UInt32 { return (x << n) | ( x >> (32 - n)) } /* the five basic functions F(), G() and H() */ func F(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 { return x ^ y ^ z } func G(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 { return (x & y) | (~x & z) } func H(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 { return (x | ~y) ^ z } func I(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 { return (x & z) | (y & ~z) } func J(_ x: UInt32, _ y: UInt32, _ z: UInt32) -> UInt32 { return x ^ (y | ~z) } /* the ten basic operations FF() through III() */ func FF(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ F(b, c, d) &+ x a = ROL(a, s) &+ e c = ROL(c, 10) } func GG(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ G(b, c, d) &+ x &+ 0x5a827999 a = ROL(a, s) &+ e c = ROL(c, 10) } func HH(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ H(b, c, d) &+ x &+ 0x6ed9eba1 a = ROL(a, s) &+ e c = ROL(c, 10) } func II(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ I(b, c, d) &+ x &+ 0x8f1bbcdc a = ROL(a, s) &+ e c = ROL(c, 10) } func JJ(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ J(b, c, d) &+ x &+ 0xa953fd4e a = ROL(a, s) &+ e c = ROL(c, 10) } func FFF(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ F(b, c, d) &+ x a = ROL(a, s) &+ e c = ROL(c, 10) } func GGG(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ G(b, c, d) &+ x &+ 0x7a6d76e9 a = ROL(a, s) &+ e c = ROL(c, 10) } func HHH(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ H(b, c, d) &+ x &+ 0x6d703ef3 a = ROL(a, s) &+ e c = ROL(c, 10) } func III(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ I(b, c, d) &+ x &+ 0x5c4dd124 a = ROL(a, s) &+ e c = ROL(c, 10) } func JJJ(_ a: inout UInt32, _ b: UInt32, _ c: inout UInt32, _ d: UInt32, _ e: UInt32, _ x: UInt32, _ s: UInt32) { a = a &+ J(b, c, d) &+ x &+ 0x50a28be6 a = ROL(a, s) &+ e c = ROL(c, 10) } // *** The function starts here *** var (aa, bb, cc, dd, ee) = MDbuf var (aaa, bbb, ccc, ddd, eee) = MDbuf /* round 1 */ FF(&aa, bb, &cc, dd, ee, X[ 0], 11) FF(&ee, aa, &bb, cc, dd, X[ 1], 14) FF(&dd, ee, &aa, bb, cc, X[ 2], 15) FF(&cc, dd, &ee, aa, bb, X[ 3], 12) FF(&bb, cc, &dd, ee, aa, X[ 4], 5) FF(&aa, bb, &cc, dd, ee, X[ 5], 8) FF(&ee, aa, &bb, cc, dd, X[ 6], 7) FF(&dd, ee, &aa, bb, cc, X[ 7], 9) FF(&cc, dd, &ee, aa, bb, X[ 8], 11) FF(&bb, cc, &dd, ee, aa, X[ 9], 13) FF(&aa, bb, &cc, dd, ee, X[10], 14) FF(&ee, aa, &bb, cc, dd, X[11], 15) FF(&dd, ee, &aa, bb, cc, X[12], 6) FF(&cc, dd, &ee, aa, bb, X[13], 7) FF(&bb, cc, &dd, ee, aa, X[14], 9) FF(&aa, bb, &cc, dd, ee, X[15], 8) /* round 2 */ GG(&ee, aa, &bb, cc, dd, X[ 7], 7) GG(&dd, ee, &aa, bb, cc, X[ 4], 6) GG(&cc, dd, &ee, aa, bb, X[13], 8) GG(&bb, cc, &dd, ee, aa, X[ 1], 13) GG(&aa, bb, &cc, dd, ee, X[10], 11) GG(&ee, aa, &bb, cc, dd, X[ 6], 9) GG(&dd, ee, &aa, bb, cc, X[15], 7) GG(&cc, dd, &ee, aa, bb, X[ 3], 15) GG(&bb, cc, &dd, ee, aa, X[12], 7) GG(&aa, bb, &cc, dd, ee, X[ 0], 12) GG(&ee, aa, &bb, cc, dd, X[ 9], 15) GG(&dd, ee, &aa, bb, cc, X[ 5], 9) GG(&cc, dd, &ee, aa, bb, X[ 2], 11) GG(&bb, cc, &dd, ee, aa, X[14], 7) GG(&aa, bb, &cc, dd, ee, X[11], 13) GG(&ee, aa, &bb, cc, dd, X[ 8], 12) /* round 3 */ HH(&dd, ee, &aa, bb, cc, X[ 3], 11) HH(&cc, dd, &ee, aa, bb, X[10], 13) HH(&bb, cc, &dd, ee, aa, X[14], 6) HH(&aa, bb, &cc, dd, ee, X[ 4], 7) HH(&ee, aa, &bb, cc, dd, X[ 9], 14) HH(&dd, ee, &aa, bb, cc, X[15], 9) HH(&cc, dd, &ee, aa, bb, X[ 8], 13) HH(&bb, cc, &dd, ee, aa, X[ 1], 15) HH(&aa, bb, &cc, dd, ee, X[ 2], 14) HH(&ee, aa, &bb, cc, dd, X[ 7], 8) HH(&dd, ee, &aa, bb, cc, X[ 0], 13) HH(&cc, dd, &ee, aa, bb, X[ 6], 6) HH(&bb, cc, &dd, ee, aa, X[13], 5) HH(&aa, bb, &cc, dd, ee, X[11], 12) HH(&ee, aa, &bb, cc, dd, X[ 5], 7) HH(&dd, ee, &aa, bb, cc, X[12], 5) /* round 4 */ II(&cc, dd, &ee, aa, bb, X[ 1], 11) II(&bb, cc, &dd, ee, aa, X[ 9], 12) II(&aa, bb, &cc, dd, ee, X[11], 14) II(&ee, aa, &bb, cc, dd, X[10], 15) II(&dd, ee, &aa, bb, cc, X[ 0], 14) II(&cc, dd, &ee, aa, bb, X[ 8], 15) II(&bb, cc, &dd, ee, aa, X[12], 9) II(&aa, bb, &cc, dd, ee, X[ 4], 8) II(&ee, aa, &bb, cc, dd, X[13], 9) II(&dd, ee, &aa, bb, cc, X[ 3], 14) II(&cc, dd, &ee, aa, bb, X[ 7], 5) II(&bb, cc, &dd, ee, aa, X[15], 6) II(&aa, bb, &cc, dd, ee, X[14], 8) II(&ee, aa, &bb, cc, dd, X[ 5], 6) II(&dd, ee, &aa, bb, cc, X[ 6], 5) II(&cc, dd, &ee, aa, bb, X[ 2], 12) /* round 5 */ JJ(&bb, cc, &dd, ee, aa, X[ 4], 9) JJ(&aa, bb, &cc, dd, ee, X[ 0], 15) JJ(&ee, aa, &bb, cc, dd, X[ 5], 5) JJ(&dd, ee, &aa, bb, cc, X[ 9], 11) JJ(&cc, dd, &ee, aa, bb, X[ 7], 6) JJ(&bb, cc, &dd, ee, aa, X[12], 8) JJ(&aa, bb, &cc, dd, ee, X[ 2], 13) JJ(&ee, aa, &bb, cc, dd, X[10], 12) JJ(&dd, ee, &aa, bb, cc, X[14], 5) JJ(&cc, dd, &ee, aa, bb, X[ 1], 12) JJ(&bb, cc, &dd, ee, aa, X[ 3], 13) JJ(&aa, bb, &cc, dd, ee, X[ 8], 14) JJ(&ee, aa, &bb, cc, dd, X[11], 11) JJ(&dd, ee, &aa, bb, cc, X[ 6], 8) JJ(&cc, dd, &ee, aa, bb, X[15], 5) JJ(&bb, cc, &dd, ee, aa, X[13], 6) /* parallel round 1 */ JJJ(&aaa, bbb, &ccc, ddd, eee, X[ 5], 8) JJJ(&eee, aaa, &bbb, ccc, ddd, X[14], 9) JJJ(&ddd, eee, &aaa, bbb, ccc, X[ 7], 9) JJJ(&ccc, ddd, &eee, aaa, bbb, X[ 0], 11) JJJ(&bbb, ccc, &ddd, eee, aaa, X[ 9], 13) JJJ(&aaa, bbb, &ccc, ddd, eee, X[ 2], 15) JJJ(&eee, aaa, &bbb, ccc, ddd, X[11], 15) JJJ(&ddd, eee, &aaa, bbb, ccc, X[ 4], 5) JJJ(&ccc, ddd, &eee, aaa, bbb, X[13], 7) JJJ(&bbb, ccc, &ddd, eee, aaa, X[ 6], 7) JJJ(&aaa, bbb, &ccc, ddd, eee, X[15], 8) JJJ(&eee, aaa, &bbb, ccc, ddd, X[ 8], 11) JJJ(&ddd, eee, &aaa, bbb, ccc, X[ 1], 14) JJJ(&ccc, ddd, &eee, aaa, bbb, X[10], 14) JJJ(&bbb, ccc, &ddd, eee, aaa, X[ 3], 12) JJJ(&aaa, bbb, &ccc, ddd, eee, X[12], 6) /* parallel round 2 */ III(&eee, aaa, &bbb, ccc, ddd, X[ 6], 9) III(&ddd, eee, &aaa, bbb, ccc, X[11], 13) III(&ccc, ddd, &eee, aaa, bbb, X[ 3], 15) III(&bbb, ccc, &ddd, eee, aaa, X[ 7], 7) III(&aaa, bbb, &ccc, ddd, eee, X[ 0], 12) III(&eee, aaa, &bbb, ccc, ddd, X[13], 8) III(&ddd, eee, &aaa, bbb, ccc, X[ 5], 9) III(&ccc, ddd, &eee, aaa, bbb, X[10], 11) III(&bbb, ccc, &ddd, eee, aaa, X[14], 7) III(&aaa, bbb, &ccc, ddd, eee, X[15], 7) III(&eee, aaa, &bbb, ccc, ddd, X[ 8], 12) III(&ddd, eee, &aaa, bbb, ccc, X[12], 7) III(&ccc, ddd, &eee, aaa, bbb, X[ 4], 6) III(&bbb, ccc, &ddd, eee, aaa, X[ 9], 15) III(&aaa, bbb, &ccc, ddd, eee, X[ 1], 13) III(&eee, aaa, &bbb, ccc, ddd, X[ 2], 11) /* parallel round 3 */ HHH(&ddd, eee, &aaa, bbb, ccc, X[15], 9) HHH(&ccc, ddd, &eee, aaa, bbb, X[ 5], 7) HHH(&bbb, ccc, &ddd, eee, aaa, X[ 1], 15) HHH(&aaa, bbb, &ccc, ddd, eee, X[ 3], 11) HHH(&eee, aaa, &bbb, ccc, ddd, X[ 7], 8) HHH(&ddd, eee, &aaa, bbb, ccc, X[14], 6) HHH(&ccc, ddd, &eee, aaa, bbb, X[ 6], 6) HHH(&bbb, ccc, &ddd, eee, aaa, X[ 9], 14) HHH(&aaa, bbb, &ccc, ddd, eee, X[11], 12) HHH(&eee, aaa, &bbb, ccc, ddd, X[ 8], 13) HHH(&ddd, eee, &aaa, bbb, ccc, X[12], 5) HHH(&ccc, ddd, &eee, aaa, bbb, X[ 2], 14) HHH(&bbb, ccc, &ddd, eee, aaa, X[10], 13) HHH(&aaa, bbb, &ccc, ddd, eee, X[ 0], 13) HHH(&eee, aaa, &bbb, ccc, ddd, X[ 4], 7) HHH(&ddd, eee, &aaa, bbb, ccc, X[13], 5) /* parallel round 4 */ GGG(&ccc, ddd, &eee, aaa, bbb, X[ 8], 15) GGG(&bbb, ccc, &ddd, eee, aaa, X[ 6], 5) GGG(&aaa, bbb, &ccc, ddd, eee, X[ 4], 8) GGG(&eee, aaa, &bbb, ccc, ddd, X[ 1], 11) GGG(&ddd, eee, &aaa, bbb, ccc, X[ 3], 14) GGG(&ccc, ddd, &eee, aaa, bbb, X[11], 14) GGG(&bbb, ccc, &ddd, eee, aaa, X[15], 6) GGG(&aaa, bbb, &ccc, ddd, eee, X[ 0], 14) GGG(&eee, aaa, &bbb, ccc, ddd, X[ 5], 6) GGG(&ddd, eee, &aaa, bbb, ccc, X[12], 9) GGG(&ccc, ddd, &eee, aaa, bbb, X[ 2], 12) GGG(&bbb, ccc, &ddd, eee, aaa, X[13], 9) GGG(&aaa, bbb, &ccc, ddd, eee, X[ 9], 12) GGG(&eee, aaa, &bbb, ccc, ddd, X[ 7], 5) GGG(&ddd, eee, &aaa, bbb, ccc, X[10], 15) GGG(&ccc, ddd, &eee, aaa, bbb, X[14], 8) /* parallel round 5 */ FFF(&bbb, ccc, &ddd, eee, aaa, X[12] , 8) FFF(&aaa, bbb, &ccc, ddd, eee, X[15] , 5) FFF(&eee, aaa, &bbb, ccc, ddd, X[10] , 12) FFF(&ddd, eee, &aaa, bbb, ccc, X[ 4] , 9) FFF(&ccc, ddd, &eee, aaa, bbb, X[ 1] , 12) FFF(&bbb, ccc, &ddd, eee, aaa, X[ 5] , 5) FFF(&aaa, bbb, &ccc, ddd, eee, X[ 8] , 14) FFF(&eee, aaa, &bbb, ccc, ddd, X[ 7] , 6) FFF(&ddd, eee, &aaa, bbb, ccc, X[ 6] , 8) FFF(&ccc, ddd, &eee, aaa, bbb, X[ 2] , 13) FFF(&bbb, ccc, &ddd, eee, aaa, X[13] , 6) FFF(&aaa, bbb, &ccc, ddd, eee, X[14] , 5) FFF(&eee, aaa, &bbb, ccc, ddd, X[ 0] , 15) FFF(&ddd, eee, &aaa, bbb, ccc, X[ 3] , 13) FFF(&ccc, ddd, &eee, aaa, bbb, X[ 9] , 11) FFF(&bbb, ccc, &ddd, eee, aaa, X[11] , 11) /* combine results */ MDbuf = (MDbuf.1 &+ cc &+ ddd, MDbuf.2 &+ dd &+ eee, MDbuf.3 &+ ee &+ aaa, MDbuf.4 &+ aa &+ bbb, MDbuf.0 &+ bb &+ ccc) } mutating private func update(data: Data) { data.withUnsafeBytes { (pointer) -> Void in guard var ptr = pointer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return } var length = data.count var X = [UInt32](repeating: 0, count: 16) // Process remaining bytes from last call: if buffer.count > 0 && buffer.count + length >= 64 { let amount = 64 - buffer.count buffer.append(ptr, count: amount) buffer.withUnsafeBytes { _ = memcpy(&X, $0.baseAddress, 64) } compress(X) ptr += amount length -= amount } // Process 64 byte chunks: while length >= 64 { memcpy(&X, ptr, 64) compress(X) ptr += 64 length -= 64 } // Save remaining unprocessed bytes: buffer = Data(bytes: ptr, count: length) } count += Int64(data.count) } mutating private func finalize() -> Data { var X = [UInt32](repeating: 0, count: 16) /* append the bit m_n == 1 */ buffer.append(0x80) buffer.withUnsafeBytes { _ = memcpy(&X, $0.baseAddress, buffer.count) } if (count & 63) > 55 { /* length goes to next block */ compress(X) X = [UInt32](repeating: 0, count: 16) } /* append length in bits */ let lswlen = UInt32(truncatingIfNeeded: count) let mswlen = UInt32(UInt64(count) >> 32) X[14] = lswlen << 3 X[15] = (lswlen >> 29) | (mswlen << 3) compress(X) var data = Data(count: 20) data.withUnsafeMutableBytes { (pointer) -> Void in let ptr = pointer.bindMemory(to: UInt32.self) ptr[0] = MDbuf.0 ptr[1] = MDbuf.1 ptr[2] = MDbuf.2 ptr[3] = MDbuf.3 ptr[4] = MDbuf.4 } buffer = Data() return data } } extension RIPEMD160 { static func hash(_ message: Data) -> Data { var md = RIPEMD160() md.update(data: message) return md.finalize() } } ================================================ FILE: HDWalletKit/Core/DataConvertable.swift ================================================ // // DataConvertable.swift // WalletKit // // Created by yuzushioh on 2018/02/11. // Copyright © 2018 yuzushioh. All rights reserved. // import Foundation protocol DataConvertable { static func +(lhs: Data, rhs: Self) -> Data static func +=(lhs: inout Data, rhs: Self) } extension DataConvertable { static func +(lhs: Data, rhs: Self) -> Data { var value = rhs let data = Data(buffer: UnsafeBufferPointer(start: &value, count: 1)) return lhs + data } static func +=(lhs: inout Data, rhs: Self) { lhs = lhs + rhs } } extension UInt8: DataConvertable {} extension UInt32: DataConvertable {} ================================================ FILE: HDWalletKit/Core/DerivationNode.swift ================================================ // // DerivationNode.swift // CryptoSwift // // Created by Pavlo Boiko on 02.07.18. // import Foundation public enum DerivationNode { case hardened(UInt32) case notHardened(UInt32) public var index: UInt32 { switch self { case .hardened(let index): return index case .notHardened(let index): return index } } public var hardens: Bool { switch self { case .hardened: return true case .notHardened: return false } } } ================================================ FILE: HDWalletKit/Core/Encodeing/Base58Encode.swift ================================================ // // Base58Encode.swift // WalletKit // // Created by yuzushioh on 2018/02/11. // Copyright © 2018 yuzushioh. All rights reserved. // import Foundation import CryptoSwift // MARK: Base56Encode //public struct Base58 { // private static let alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" // // static func base58FromBytes(_ bytes: [UInt8]) -> String { // var bytes = bytes // var zerosCount = 0 // var length = 0 // // for b in bytes { // if b != 0 { break } // zerosCount += 1 // } // // bytes.removeFirst(zerosCount) // // let size = bytes.count * 138 / 100 + 1 // // var base58: [UInt8] = Array(repeating: 0, count: size) // for b in bytes { // var carry = Int(b) // var i = 0 // // for j in 0...base58.count-1 where carry != 0 || i < length { // carry += 256 * Int(base58[base58.count - j - 1]) // base58[base58.count - j - 1] = UInt8(carry % 58) // carry /= 58 // i += 1 // } // // assert(carry == 0) // // length = i // } // // // skip leading zeros // var zerosToRemove = 0 // var str = "" // for b in base58 { // if b != 0 { break } // zerosToRemove += 1 // } // base58.removeFirst(zerosToRemove) // // while 0 < zerosCount { // str = "\(str)1" // zerosCount -= 1 // } // // for b in base58 { // str = "\(str)\(alphabet[String.Index(encodedOffset: Int(b))])" // } // // return str // } // // // Decode // static func bytesFromBase58(_ base58: String) -> [UInt8] { // // remove leading and trailing whitespaces // let string = base58.trimmingCharacters(in: CharacterSet.whitespaces) // // guard !string.isEmpty else { return [] } // // var zerosCount = 0 // var length = 0 // for c in string { // if c != "1" { break } // zerosCount += 1 // } // // let size = string.lengthOfBytes(using: String.Encoding.utf8) * 733 / 1000 + 1 - zerosCount // var base58: [UInt8] = Array(repeating: 0, count: size) // for c in string where c != " " { // // search for base58 character // guard let base58Index = alphabet.index(of: c) else { return [] } // // var carry = base58Index.encodedOffset // var i = 0 // for j in 0...base58.count where carry != 0 || i < length { // carry += 58 * Int(base58[base58.count - j - 1]) // base58[base58.count - j - 1] = UInt8(carry % 256) // carry /= 256 // i += 1 // } // // assert(carry == 0) // length = i // } // // // skip leading zeros // var zerosToRemove = 0 // // for b in base58 { // if b != 0 { break } // zerosToRemove += 1 // } // base58.removeFirst(zerosToRemove) // // var result: [UInt8] = Array(repeating: 0, count: zerosCount) // for b in base58 { // result.append(b) // } // return result // } //} ================================================ FILE: HDWalletKit/Core/Encodeing/Bech32.swift ================================================ // // Bech58.swift // HDWalletKit // // Created by Pavlo Boiko on 2/5/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation private protocol Encoding { static var baseAlphabets: String { get } static var zeroAlphabet: Character { get } static var base: Int { get } // log(256) / log(base), rounded up static func sizeFromByte(size: Int) -> Int // log(base) / log(256), rounded up static func sizeFromBase(size: Int) -> Int // Public static func encode(_ bytes: Data) -> String static func decode(_ string: String) -> Data } private struct _Base58: Encoding { static let baseAlphabets = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" static var zeroAlphabet: Character = "1" static var base: Int = 58 static func sizeFromByte(size: Int) -> Int { return size * 138 / 100 + 1 } static func sizeFromBase(size: Int) -> Int { return size * 733 / 1000 + 1 } } public struct Base58 { public static func encode(_ bytes: Data) -> String { return _Base58.encode(bytes) } public static func decode(_ string: String) -> Data? { return _Base58.decode(string) } } // The Base encoding used is home made, and has some differences. Especially, // leading zeros are kept as single zeros when conversion happens. extension Encoding { static func convertBytesToBase(_ bytes: Data) -> [UInt8] { var length = 0 let size = sizeFromByte(size: bytes.count) var encodedBytes: [UInt8] = Array(repeating: 0, count: size) for b in bytes { var carry = Int(b) var i = 0 for j in (0...encodedBytes.count - 1).reversed() where carry != 0 || i < length { carry += 256 * Int(encodedBytes[j]) encodedBytes[j] = UInt8(carry % base) carry /= base i += 1 } assert(carry == 0) length = i } var zerosToRemove = 0 for b in encodedBytes { if b != 0 { break } zerosToRemove += 1 } encodedBytes.removeFirst(zerosToRemove) return encodedBytes } static func encode(_ bytes: Data) -> String { var bytes = bytes var zerosCount = 0 for b in bytes { if b != 0 { break } zerosCount += 1 } bytes.removeFirst(zerosCount) let encodedBytes = convertBytesToBase(bytes) var str = "" while 0 < zerosCount { str += String(zeroAlphabet) zerosCount -= 1 } for b in encodedBytes { str += String(baseAlphabets[String.Index(utf16Offset: Int(b), in: baseAlphabets)]) } return str } static func decode(_ string: String) -> Data { guard !string.isEmpty else { return Data() } var zerosCount = 0 var length = 0 for c in string { if c != zeroAlphabet { break } zerosCount += 1 } let size = sizeFromBase(size: string.lengthOfBytes(using: .utf8) - zerosCount) var decodedBytes: [UInt8] = Array(repeating: 0, count: size) for c in string { guard let baseIndex = baseAlphabets.firstIndex(of: c) else { return Data() } var carry = baseIndex.utf16Offset(in: baseAlphabets) var i = 0 for j in (0...decodedBytes.count - 1).reversed() where carry != 0 || i < length { carry += base * Int(decodedBytes[j]) decodedBytes[j] = UInt8(carry % 256) carry /= 256 i += 1 } assert(carry == 0) length = i } // skip leading zeros var zerosToRemove = 0 for b in decodedBytes { if b != 0 { break } zerosToRemove += 1 } decodedBytes.removeFirst(zerosToRemove) return Data(repeating: 0, count: zerosCount) + Data(decodedBytes) } } public struct Bech32 { private static let base32Alphabets = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" public static func encode(_ bytes: Data, prefix: String, seperator: String = ":") -> String { let payload = convertTo5bit(data: bytes, pad: true) let checksum: Data = createChecksum(prefix: prefix, payload: payload) // Data of [UInt5] let combined: Data = payload + checksum // Data of [UInt5] var base32 = "" for b in combined { base32 += String(base32Alphabets[String.Index(utf16Offset: Int(b), in: base32Alphabets)]) } return prefix + seperator + base32 } // string : "bitcoincash:qql8zpwglr3q5le9jnjxkmypefaku39dkygsx29fzk" public static func decode(_ string: String, seperator: String = ":") -> (prefix: String, data: Data)? { // We can't have empty string. // Bech32 should be uppercase only / lowercase only. guard !string.isEmpty && [string.lowercased(), string.uppercased()].contains(string) else { return nil } let components = string.components(separatedBy: seperator) // We can only handle string contains both scheme and base32 guard components.count == 2 else { return nil } let (prefix, base32) = (components[0], components[1]) var decodedIn5bit: [UInt8] = [UInt8]() for c in base32.lowercased() { // We can't have characters other than base32 alphabets. guard let baseIndex = base32Alphabets.firstIndex(of: c)?.utf16Offset(in: base32Alphabets) else { return nil } decodedIn5bit.append(UInt8(baseIndex)) } // We can't have invalid checksum let payload = Data(decodedIn5bit) guard verifyChecksum(prefix: prefix, payload: payload) else { return nil } // Drop checksum guard let bytes = try? convertFrom5bit(data: payload.dropLast(8)) else { return nil } return (prefix, Data(bytes)) } private static func verifyChecksum(prefix: String, payload: Data) -> Bool { return PolyMod(expand(prefix) + payload) == 0 } private static func expand(_ prefix: String) -> Data { var ret: Data = Data() let buf: [UInt8] = Array(prefix.utf8) for b in buf { ret += b & 0x1f } ret += Data(repeating: 0, count: 1) return ret } private static func createChecksum(prefix: String, payload: Data) -> Data { let enc: Data = expand(prefix) + payload + Data(repeating: 0, count: 8) let mod: UInt64 = PolyMod(enc) var ret: Data = Data() for i in 0..<8 { ret += UInt8((mod >> (5 * (7 - i))) & 0x1f) } return ret } private static func PolyMod(_ data: Data) -> UInt64 { var c: UInt64 = 1 for d in data { let c0: UInt8 = UInt8(c >> 35) c = ((c & 0x07ffffffff) << 5) ^ UInt64(d) if c0 & 0x01 != 0 { c ^= 0x98f2bc8e61 } if c0 & 0x02 != 0 { c ^= 0x79b76d99e2 } if c0 & 0x04 != 0 { c ^= 0xf33e5fb3c4 } if c0 & 0x08 != 0 { c ^= 0xae2eabe2a8 } if c0 & 0x10 != 0 { c ^= 0x1e4f43e470 } } return c ^ 1 } private static func convertTo5bit(data: Data, pad: Bool) -> Data { var acc = Int() var bits = UInt8() let maxv: Int = 31 // 31 = 0x1f = 00011111 var converted: [UInt8] = [] for d in data { acc = (acc << 8) | Int(d) bits += 8 while bits >= 5 { bits -= 5 converted.append(UInt8(acc >> Int(bits) & maxv)) } } let lastBits: UInt8 = UInt8(acc << (5 - bits) & maxv) if pad && bits > 0 { converted.append(lastBits) } return Data(converted) } internal static func convertFrom5bit(data: Data) throws -> Data { var acc = Int() var bits = UInt8() let maxv: Int = 255 // 255 = 0xff = 11111111 var converted: [UInt8] = [] for d in data { guard (d >> 5) == 0 else { throw DecodeError.invalidCharacter } acc = (acc << 5) | Int(d) bits += 5 while bits >= 8 { bits -= 8 converted.append(UInt8(acc >> Int(bits) & maxv)) } } let lastBits: UInt8 = UInt8(acc << (8 - bits) & maxv) guard bits < 5 && lastBits == 0 else { throw DecodeError.invalidBits } return Data(converted) } private enum DecodeError: Error { case invalidCharacter case invalidBits } } ================================================ FILE: HDWalletKit/Core/Encodeing/EIP55.swift ================================================ // // EIP55.swift // HDWalletKit // // Created by Pavlo Boiko on 28.06.18. // import CryptoSwift // NOTE: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md public struct EIP55 { public static func encode(_ data: Data) -> String { let address = data.toHexString() let hash = Crypto.sha3keccak256(data: address.data(using: .ascii)!).toHexString() return zip(address, hash) .map { a, h -> String in switch (a, h) { case ("0", _), ("1", _), ("2", _), ("3", _), ("4", _), ("5", _), ("6", _), ("7", _), ("8", _), ("9", _): return String(a) case (_, "8"), (_, "9"), (_, "a"), (_, "b"), (_, "c"), (_, "d"), (_, "e"), (_, "f"): return String(a).uppercased() default: return String(a).lowercased() } } .joined() } } ================================================ FILE: HDWalletKit/Core/Encodeing/RLP.swift ================================================ import Foundation public struct RLP { public static func encode(_ element: Any) throws -> Data { let encoded: Data? switch element { case let list as [Any]: encoded = try encode(elements: list) case let bint as BInt: encoded = encode(bint: bint) case let int as Int: encoded = encode(bint: BInt(int)) case let data as Data: encoded = encode(data: data) case let string as String: encoded = encode(string: string) default: encoded = nil } guard let data = encoded else { throw HDWalletKitError.cryptoError(.failedToEncode(element: element)) } return data } private static func encode(data: Data) -> Data { if data.count == 1 && data[0] <= 0x7f { return data } var encoded = encodeHeader(size: UInt64(data.count), smallTag: 0x80, largeTag: 0xb7) encoded.append(data) return encoded } private static func encode(string: String) -> Data? { guard let data = string.data(using: .utf8) else { return nil } return encode(data: data) } private static func encode(bint: BInt) -> Data? { let data = bint.serialize() if data.isEmpty { return Data([0x80]) } return encode(data: data) } private static func encode(elements: [Any]) throws -> Data? { var data = Data() for element in elements { data.append(try encode(element)) } var encodedData = encodeHeader(size: UInt64(data.count), smallTag: 0xc0, largeTag: 0xf7) encodedData.append(data) return encodedData } private static func encodeHeader(size: UInt64, smallTag: UInt8, largeTag: UInt8) -> Data { if size < 56 { return Data([smallTag + UInt8(size)]) } let sizeData = putint(size) var encoded = Data() encoded.append(largeTag + UInt8(sizeData.count)) encoded.append(contentsOf: sizeData) return encoded } private static func putint(_ i: UInt64) -> Data { switch i { case 0 ..< (1 << 8): return Data([UInt8(i)]) case 0 ..< (1 << 16): return Data([ UInt8(i >> 8), UInt8(truncatingIfNeeded: i) ]) case 0 ..< (1 << 24): return Data([ UInt8(i >> 16), UInt8(truncatingIfNeeded: i >> 8), UInt8(truncatingIfNeeded: i) ]) case 0 ..< (1 << 32): return Data([ UInt8(i >> 24), UInt8(truncatingIfNeeded: i >> 16), UInt8(truncatingIfNeeded: i >> 8), UInt8(truncatingIfNeeded: i) ]) case 0 ..< (1 << 40): return Data([ UInt8(i >> 32), UInt8(truncatingIfNeeded: i >> 24), UInt8(truncatingIfNeeded: i >> 16), UInt8(truncatingIfNeeded: i >> 8), UInt8(truncatingIfNeeded: i) ]) case 0 ..< (1 << 48): return Data([ UInt8(i >> 40), UInt8(truncatingIfNeeded: i >> 32), UInt8(truncatingIfNeeded: i >> 24), UInt8(truncatingIfNeeded: i >> 16), UInt8(truncatingIfNeeded: i >> 8), UInt8(truncatingIfNeeded: i) ]) case 0 ..< (1 << 56): return Data([ UInt8(i >> 48), UInt8(truncatingIfNeeded: i >> 40), UInt8(truncatingIfNeeded: i >> 32), UInt8(truncatingIfNeeded: i >> 24), UInt8(truncatingIfNeeded: i >> 16), UInt8(truncatingIfNeeded: i >> 8), UInt8(truncatingIfNeeded: i) ]) default: return Data([ UInt8(i >> 56), UInt8(truncatingIfNeeded: i >> 48), UInt8(truncatingIfNeeded: i >> 40), UInt8(truncatingIfNeeded: i >> 32), UInt8(truncatingIfNeeded: i >> 24), UInt8(truncatingIfNeeded: i >> 16), UInt8(truncatingIfNeeded: i >> 8), UInt8(truncatingIfNeeded: i) ]) } } } ================================================ FILE: HDWalletKit/Core/Error/HDWalletKitError.swift ================================================ // // HDWalletKitError.swift // HDWalletKit // // Created by Pavlo Boiko on 12.07.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public enum HDWalletKitError: Error { public enum CryptoError { case failedToEncode(element:Any) } public enum ContractError: Error { case containsInvalidCharactor(Any) case invalidDecimalValue(Any) } public enum ConvertError: Error { case failedToConvert(Any) } case cryptoError(CryptoError) case contractError(ContractError) case convertError(ConvertError) case failedToSign case noEnoughSpace case unknownError } ================================================ FILE: HDWalletKit/Core/Extensions/Data+Random.swift ================================================ // // Data+Random.swift // HDWalletKit // // Created by Pavlo Boiko on 20.08.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation extension Data { static func randomBytes(length: Int) -> Data { var bytes = Data(count: length) _ = bytes.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, length, $0.baseAddress!) } return bytes } } ================================================ FILE: HDWalletKit/Core/Extensions/Data+Script.swift ================================================ // // Data+Script.swift // HDWalletKit // // Created by Pavlo Boiko on 1/4/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation // swiftlint:disable shorthand_operator // swiftlint:disable operator_whitespace protocol BinaryConvertible { static func +(lhs: Data, rhs: Self) -> Data static func +=(lhs: inout Data, rhs: Self) } extension BinaryConvertible { static func +(lhs: Data, rhs: Self) -> Data { var value = rhs let data = Data(buffer: UnsafeBufferPointer(start: &value, count: 1)) return lhs + data } static func +=(lhs: inout Data, rhs: Self) { lhs = lhs + rhs } } extension UInt16: BinaryConvertible {} extension UInt64: BinaryConvertible {} extension Int8: BinaryConvertible {} extension Int16: BinaryConvertible {} extension Int32: BinaryConvertible {} extension Int64: BinaryConvertible {} extension Int: BinaryConvertible {} extension Bool: BinaryConvertible { static func +(lhs: Data, rhs: Bool) -> Data { return lhs + (rhs ? UInt8(0x01) : UInt8(0x00)).littleEndian } } extension String: BinaryConvertible { static func +(lhs: Data, rhs: String) -> Data { guard let data = rhs.data(using: .ascii) else { return lhs } return lhs + data } } func +(lhs: Data, rhs: OpCodeProtocol) -> Data { return lhs + rhs.value } func += (lhs: inout Data, rhs: OpCodeProtocol) { lhs = lhs + rhs } extension Data: BinaryConvertible { static func +(lhs: Data, rhs: Data) -> Data { var data = Data() data.append(lhs) data.append(rhs) return data } } extension Data { init(from value: T) { var value = value self.init(buffer: UnsafeBufferPointer(start: &value, count: 1)) } func to(type: T.Type) -> T { return self.withUnsafeBytes { (ptr) -> T in return ptr.baseAddress!.assumingMemoryBound(to: T.self).pointee } } func to(type: String.Type) -> String { return String(bytes: self, encoding: .ascii)!.replacingOccurrences(of: "\0", with: "") } func to(type: VarInt.Type) -> VarInt { let value: UInt64 let length = self[0..<1].to(type: UInt8.self) switch length { case 0...252: value = UInt64(length) case 0xfd: value = UInt64(self[1...2].to(type: UInt16.self)) case 0xfe: value = UInt64(self[1...4].to(type: UInt32.self)) case 0xff: fallthrough default: value = self[1...8].to(type: UInt64.self) } return VarInt(value) } } extension Data { public var hex: String { return reduce("") { $0 + String(format: "%02x", $1) } } } ================================================ FILE: HDWalletKit/Core/Extensions/String+Hex.swift ================================================ // // String+Hex.swift // HDWalletKit // // Created by Pavlo Boiko on 12.07.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation fileprivate var hexPrefix = "0x" extension String { public func stripHexPrefix() -> String { var hex = self if hex.hasPrefix(hexPrefix) { hex = String(hex.dropFirst(hexPrefix.count)) } return hex } public func addHexPrefix() -> String { return hexPrefix.appending(self) } public func toHexString() -> String { guard let data = data(using: .utf8) else { return "" } return data.toHexString() } } extension Data { public func dataToHexString() -> String { return map { String(format: "%02x", $0) }.joined() } public static func fromHex(_ hex: String) -> Data? { let string = hex.lowercased().stripHexPrefix() let array = Array(hex: string) if (array.count == 0) { if (hex == "0x" || hex == "") { return Data() } else { return nil } } return Data(array) } public func constantTimeComparisonTo(_ other:Data?) -> Bool { guard let rhs = other else {return false} guard self.count == rhs.count else {return false} var difference = UInt8(0x00) for i in 0.. Data { return data } public static func deserialize(_ data: Data) -> VarInt { return data.to(type: self) } } extension VarInt: CustomStringConvertible { public var description: String { return "\(underlyingValue)" } } ================================================ FILE: HDWalletKit/Core/VarString.swift ================================================ // // VarString.swift // HDWalletKit // // Created by Pavlo Boiko on 1/6/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation /// Variable length string can be stored using a variable length integer followed by the string itself. public struct VarString: ExpressibleByStringLiteral { public typealias StringLiteralType = String public let length: VarInt public let value: String public init(stringLiteral value: String) { self.init(value) } public init(_ value: String) { self.value = value length = VarInt(value.data(using: .ascii)!.count) } public func serialized() -> Data { var data = Data() data += length.serialized() data += value return data } } extension VarString: CustomStringConvertible { public var description: String { return "\(value)" } } ================================================ FILE: HDWalletKit/Keystore/KeystoreInterface.swift ================================================ // // KeystoreInterface.swift // HDWalletKit // // Created by Pavlo Boiko on 20.08.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public enum KeystoreError: Error { case keyDerivationError case aesError } protocol KeystoreInterface { func getDecriptedKeyStore(passwordData: Data) throws -> Data? func encodedData() throws -> Data init? (data: Data, passwordData: Data) throws init? (keyStore: Data) throws init? (data: Data, password: String) throws func getDecriptedKeyStore(password: String) throws -> Data? } ================================================ FILE: HDWalletKit/Keystore/KeystoreV3.swift ================================================ // // KeystoreV3.swift // HDWalletKit // // Created by Pavlo Boiko on 20.08.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation import CryptoSwift public class KeystoreV3: KeystoreInterface { @available(*, deprecated) /// Init with raw pasword /// We will automaticaly hash password to sha3-keccak256 /// required public convenience init?(data: Data, password: String) throws { guard let passwordData = password.data(using: .utf8)?.sha3(.keccak256) else { return nil } try self.init(data: data, passwordData: passwordData) } /// Init with encoded pasword /// public required init? (data: Data, passwordData: Data) throws { try encryptDataToStorage(passwordData, data: data) } public required init? (keyStore: Data) throws { keystoreParams = try JSONDecoder().decode(KeystoreParamsV3.self, from: keyStore) } public var keystoreParams: KeystoreParamsV3? public func encodedData() throws -> Data { return try JSONEncoder().encode(keystoreParams) } @available(*, deprecated) /// Decode keystore with password /// We will automaticaly hash password to sha3-keccak256 /// /// - Parameter password: raw password /// - Returns: decripted keystore value /// - Throws: wrong password error func getDecriptedKeyStore(password: String) throws -> Data? { guard let passwordData = password.data(using: .utf8)?.sha3(.keccak256) else { return nil } return try getDecriptedKeyStore(passwordData: passwordData) } /// Decode keystore with password /// /// - Parameter password: encoded password /// - Returns: decripted keystore value /// - Throws: wrong password error public func getDecriptedKeyStore(passwordData: Data) throws -> Data? { guard let keystoreParams = self.keystoreParams else {return nil} guard let saltData = Data.fromHex(keystoreParams.crypto.kdfparams.salt) else {return nil} let derivedLen = keystoreParams.crypto.kdfparams.dklen guard let N = keystoreParams.crypto.kdfparams.n else {return nil} guard let P = keystoreParams.crypto.kdfparams.p else {return nil} guard let R = keystoreParams.crypto.kdfparams.r else {return nil} guard let derivedKey = encryptData(passwordData: passwordData, salt: saltData, length: derivedLen, N: N, R: R, P: P) else {return nil} var dataForMAC = Data() let derivedKeyLast16bytes = Data(derivedKey[(derivedKey.count - 16)...(derivedKey.count - 1)]) dataForMAC.append(derivedKeyLast16bytes) guard let cipherText = Data.fromHex(keystoreParams.crypto.ciphertext) else {return nil} dataForMAC.append(cipherText) let mac = dataForMAC.sha3(.keccak256) guard let calculatedMac = Data.fromHex(keystoreParams.crypto.mac), mac.constantTimeComparisonTo(calculatedMac) else {return nil} let decryptionKey = derivedKey[0...15] guard let IV = Data.fromHex(keystoreParams.crypto.cipherparams.iv) else {return nil} guard let aesCipher = try? AES(key: decryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .noPadding) else {return nil} guard let decryptedPK:Array = try? aesCipher.decrypt(cipherText.bytes) else { return nil } return Data(decryptedPK) } private func encryptData(passwordData: Data, salt: Data, length: Int, N: Int, R: Int, P: Int) -> Data? { guard let deriver = try? Scrypt(password: passwordData.bytes, salt: salt.bytes, dkLen: length, N: N, r: R, p: P) else {return nil} guard let result = try? deriver.calculate() else {return nil} return Data(result) } private func encryptDataToStorage(_ passwordData: Data, data: Data, dkLen: Int=32, N: Int = 1024, R: Int = 8, P: Int = 1) throws { let saltLen = 32; let saltData = Data.randomBytes(length: saltLen) guard let derivedKey = encryptData(passwordData: passwordData, salt: saltData, length: dkLen, N: N, R: R, P: P) else {throw KeystoreError.keyDerivationError} let last16bytes = Data(derivedKey[(derivedKey.count - 16)...(derivedKey.count-1)]) let encryptionKey = Data(derivedKey[0...15]) let IV = Data.randomBytes(length: 16) let aesCipher = try? AES(key: encryptionKey.bytes, blockMode: CTR(iv: IV.bytes), padding: .noPadding) guard let encryptedKey = try aesCipher?.encrypt(data.bytes) else { throw KeystoreError.aesError } let encryptedKeyData = Data(encryptedKey) var dataForMAC = Data() dataForMAC.append(last16bytes) dataForMAC.append(encryptedKeyData) let mac = dataForMAC.sha3(.keccak256) let kdfparams = KeystoreParamsV3.CryptoParamsV3.KdfParamsV3(salt: saltData.toHexString(), dklen: dkLen, n: N, p: P, r: R) let cipherparams = KeystoreParamsV3.CryptoParamsV3.CipherParamsV3(iv: IV.toHexString()) let crypto = KeystoreParamsV3.CryptoParamsV3(ciphertext: encryptedKeyData.toHexString(), cipher: "aes-128-ctr", cipherparams: cipherparams, kdf: "scrypt", kdfparams: kdfparams, mac: mac.toHexString(), version: nil) let keystoreparams = KeystoreParamsV3(crypto: crypto, id: UUID().uuidString.lowercased(), version: 3) self.keystoreParams = keystoreparams } } ================================================ FILE: HDWalletKit/Keystore/KeystoreV3Json.swift ================================================ // // KeystoreV3Json.swift // HDWalletKit // // Created by Pavlo Boiko on 19.08.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public struct KeystoreParamsV3: Codable { var crypto: CryptoParamsV3 var id: String? var version: Int public init(crypto cr: KeystoreParamsV3.CryptoParamsV3, id i: String, version ver: Int) { crypto = cr id = i version = ver } public struct CryptoParamsV3: Codable { var ciphertext: String var cipher: String var cipherparams: CipherParamsV3 var kdf: String var kdfparams: KdfParamsV3 var mac: String var version: String? public struct KdfParamsV3: Codable { var salt: String var dklen: Int var n: Int? var p: Int? var r: Int? } public struct CipherParamsV3: Codable { var iv: String } } private enum CodingKeys: String, CodingKey { case crypto = "Crypto" case id, version } } ================================================ FILE: HDWalletKit/Mnemonic/Mnemonic.swift ================================================ // // Mnemonic.swift // WalletKit // // Created by yuzushioh on 2018/02/11. // Copyright © 2018 yuzushioh. All rights reserved. // import Foundation // https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki public final class Mnemonic { public enum Strength: Int { case normal = 128 case hight = 256 } public static func create(strength: Strength = .normal, language: WordList = .english) -> String { let byteCount = strength.rawValue / 8 let bytes = Data.randomBytes(length: byteCount) return create(entropy: bytes, language: language) } public static func create(entropy: Data, language: WordList = .english) -> String { let entropybits = String(entropy.flatMap { ("00000000" + String($0, radix: 2)).suffix(8) }) let hashBits = String(entropy.sha256().flatMap { ("00000000" + String($0, radix: 2)).suffix(8) }) let checkSum = String(hashBits.prefix((entropy.count * 8) / 32)) let words = language.words let concatenatedBits = entropybits + checkSum var mnemonic: [String] = [] for index in 0..<(concatenatedBits.count / 11) { let startIndex = concatenatedBits.index(concatenatedBits.startIndex, offsetBy: index * 11) let endIndex = concatenatedBits.index(startIndex, offsetBy: 11) let wordIndex = Int(strtoul(String(concatenatedBits[startIndex.. Data { guard let password = mnemonic.decomposedStringWithCompatibilityMapping.data(using: .utf8) else { fatalError("Nomalizing password failed in \(self)") } guard let salt = ("mnemonic" + passphrase).decomposedStringWithCompatibilityMapping.data(using: .utf8) else { fatalError("Nomalizing salt failed in \(self)") } return Crypto.PBKDF2SHA512(password: password.bytes, salt: salt.bytes) } } ================================================ FILE: HDWalletKit/Mnemonic/WordList.swift ================================================ // // WordList.swift // WalletKit // // Created by yuzushioh on 2018/01/01. // Copyright © 2018 yuzushioh. All rights reserved. // public enum WordList { case english case japanese case korean case spanish case simplifiedChinese case traditionalChinese case french case italian public var words: [String] { switch self { case .english: return Constants.englishWords case .japanese: return Constants.japaneseWords case .korean: return Constants.koreanWords case .spanish: return Constants.spanishWords case .simplifiedChinese: return Constants.simplifiedChineseWords case .traditionalChinese: return Constants.traditionalChineseWords case .french: return Constants.frenchWords case .italian: return Constants.italianWords } } } fileprivate struct Constants { static var englishWords: [String] = ["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"] static var japaneseWords: [String] = ["あいこくしん", "あいさつ", "あいだ", "あおぞら", "あかちゃん", "あきる", "あけがた", "あける", "あこがれる", "あさい", "あさひ", "あしあと", "あじわう", "あずかる", "あずき", "あそぶ", "あたえる", "あたためる", "あたりまえ", "あたる", "あつい", "あつかう", "あっしゅく", "あつまり", "あつめる", "あてな", "あてはまる", "あひる", "あぶら", "あぶる", "あふれる", "あまい", "あまど", "あまやかす", "あまり", "あみもの", "あめりか", "あやまる", "あゆむ", "あらいぐま", "あらし", "あらすじ", "あらためる", "あらゆる", "あらわす", "ありがとう", "あわせる", "あわてる", "あんい", "あんがい", "あんこ", "あんぜん", "あんてい", "あんない", "あんまり", "いいだす", "いおん", "いがい", "いがく", "いきおい", "いきなり", "いきもの", "いきる", "いくじ", "いくぶん", "いけばな", "いけん", "いこう", "いこく", "いこつ", "いさましい", "いさん", "いしき", "いじゅう", "いじょう", "いじわる", "いずみ", "いずれ", "いせい", "いせえび", "いせかい", "いせき", "いぜん", "いそうろう", "いそがしい", "いだい", "いだく", "いたずら", "いたみ", "いたりあ", "いちおう", "いちじ", "いちど", "いちば", "いちぶ", "いちりゅう", "いつか", "いっしゅん", "いっせい", "いっそう", "いったん", "いっち", "いってい", "いっぽう", "いてざ", "いてん", "いどう", "いとこ", "いない", "いなか", "いねむり", "いのち", "いのる", "いはつ", "いばる", "いはん", "いびき", "いひん", "いふく", "いへん", "いほう", "いみん", "いもうと", "いもたれ", "いもり", "いやがる", "いやす", "いよかん", "いよく", "いらい", "いらすと", "いりぐち", "いりょう", "いれい", "いれもの", "いれる", "いろえんぴつ", "いわい", "いわう", "いわかん", "いわば", "いわゆる", "いんげんまめ", "いんさつ", "いんしょう", "いんよう", "うえき", "うえる", "うおざ", "うがい", "うかぶ", "うかべる", "うきわ", "うくらいな", "うくれれ", "うけたまわる", "うけつけ", "うけとる", "うけもつ", "うける", "うごかす", "うごく", "うこん", "うさぎ", "うしなう", "うしろがみ", "うすい", "うすぎ", "うすぐらい", "うすめる", "うせつ", "うちあわせ", "うちがわ", "うちき", "うちゅう", "うっかり", "うつくしい", "うったえる", "うつる", "うどん", "うなぎ", "うなじ", "うなずく", "うなる", "うねる", "うのう", "うぶげ", "うぶごえ", "うまれる", "うめる", "うもう", "うやまう", "うよく", "うらがえす", "うらぐち", "うらない", "うりあげ", "うりきれ", "うるさい", "うれしい", "うれゆき", "うれる", "うろこ", "うわき", "うわさ", "うんこう", "うんちん", "うんてん", "うんどう", "えいえん", "えいが", "えいきょう", "えいご", "えいせい", "えいぶん", "えいよう", "えいわ", "えおり", "えがお", "えがく", "えきたい", "えくせる", "えしゃく", "えすて", "えつらん", "えのぐ", "えほうまき", "えほん", "えまき", "えもじ", "えもの", "えらい", "えらぶ", "えりあ", "えんえん", "えんかい", "えんぎ", "えんげき", "えんしゅう", "えんぜつ", "えんそく", "えんちょう", "えんとつ", "おいかける", "おいこす", "おいしい", "おいつく", "おうえん", "おうさま", "おうじ", "おうせつ", "おうたい", "おうふく", "おうべい", "おうよう", "おえる", "おおい", "おおう", "おおどおり", "おおや", "おおよそ", "おかえり", "おかず", "おがむ", "おかわり", "おぎなう", "おきる", "おくさま", "おくじょう", "おくりがな", "おくる", "おくれる", "おこす", "おこなう", "おこる", "おさえる", "おさない", "おさめる", "おしいれ", "おしえる", "おじぎ", "おじさん", "おしゃれ", "おそらく", "おそわる", "おたがい", "おたく", "おだやか", "おちつく", "おっと", "おつり", "おでかけ", "おとしもの", "おとなしい", "おどり", "おどろかす", "おばさん", "おまいり", "おめでとう", "おもいで", "おもう", "おもたい", "おもちゃ", "おやつ", "おやゆび", "およぼす", "おらんだ", "おろす", "おんがく", "おんけい", "おんしゃ", "おんせん", "おんだん", "おんちゅう", "おんどけい", "かあつ", "かいが", "がいき", "がいけん", "がいこう", "かいさつ", "かいしゃ", "かいすいよく", "かいぜん", "かいぞうど", "かいつう", "かいてん", "かいとう", "かいふく", "がいへき", "かいほう", "かいよう", "がいらい", "かいわ", "かえる", "かおり", "かかえる", "かがく", "かがし", "かがみ", "かくご", "かくとく", "かざる", "がぞう", "かたい", "かたち", "がちょう", "がっきゅう", "がっこう", "がっさん", "がっしょう", "かなざわし", "かのう", "がはく", "かぶか", "かほう", "かほご", "かまう", "かまぼこ", "かめれおん", "かゆい", "かようび", "からい", "かるい", "かろう", "かわく", "かわら", "がんか", "かんけい", "かんこう", "かんしゃ", "かんそう", "かんたん", "かんち", "がんばる", "きあい", "きあつ", "きいろ", "ぎいん", "きうい", "きうん", "きえる", "きおう", "きおく", "きおち", "きおん", "きかい", "きかく", "きかんしゃ", "ききて", "きくばり", "きくらげ", "きけんせい", "きこう", "きこえる", "きこく", "きさい", "きさく", "きさま", "きさらぎ", "ぎじかがく", "ぎしき", "ぎじたいけん", "ぎじにってい", "ぎじゅつしゃ", "きすう", "きせい", "きせき", "きせつ", "きそう", "きぞく", "きぞん", "きたえる", "きちょう", "きつえん", "ぎっちり", "きつつき", "きつね", "きてい", "きどう", "きどく", "きない", "きなが", "きなこ", "きぬごし", "きねん", "きのう", "きのした", "きはく", "きびしい", "きひん", "きふく", "きぶん", "きぼう", "きほん", "きまる", "きみつ", "きむずかしい", "きめる", "きもだめし", "きもち", "きもの", "きゃく", "きやく", "ぎゅうにく", "きよう", "きょうりゅう", "きらい", "きらく", "きりん", "きれい", "きれつ", "きろく", "ぎろん", "きわめる", "ぎんいろ", "きんかくじ", "きんじょ", "きんようび", "ぐあい", "くいず", "くうかん", "くうき", "くうぐん", "くうこう", "ぐうせい", "くうそう", "ぐうたら", "くうふく", "くうぼ", "くかん", "くきょう", "くげん", "ぐこう", "くさい", "くさき", "くさばな", "くさる", "くしゃみ", "くしょう", "くすのき", "くすりゆび", "くせげ", "くせん", "ぐたいてき", "くださる", "くたびれる", "くちこみ", "くちさき", "くつした", "ぐっすり", "くつろぐ", "くとうてん", "くどく", "くなん", "くねくね", "くのう", "くふう", "くみあわせ", "くみたてる", "くめる", "くやくしょ", "くらす", "くらべる", "くるま", "くれる", "くろう", "くわしい", "ぐんかん", "ぐんしょく", "ぐんたい", "ぐんて", "けあな", "けいかく", "けいけん", "けいこ", "けいさつ", "げいじゅつ", "けいたい", "げいのうじん", "けいれき", "けいろ", "けおとす", "けおりもの", "げきか", "げきげん", "げきだん", "げきちん", "げきとつ", "げきは", "げきやく", "げこう", "げこくじょう", "げざい", "けさき", "げざん", "けしき", "けしごむ", "けしょう", "げすと", "けたば", "けちゃっぷ", "けちらす", "けつあつ", "けつい", "けつえき", "けっこん", "けつじょ", "けっせき", "けってい", "けつまつ", "げつようび", "げつれい", "けつろん", "げどく", "けとばす", "けとる", "けなげ", "けなす", "けなみ", "けぬき", "げねつ", "けねん", "けはい", "げひん", "けぶかい", "げぼく", "けまり", "けみかる", "けむし", "けむり", "けもの", "けらい", "けろけろ", "けわしい", "けんい", "けんえつ", "けんお", "けんか", "げんき", "けんげん", "けんこう", "けんさく", "けんしゅう", "けんすう", "げんそう", "けんちく", "けんてい", "けんとう", "けんない", "けんにん", "げんぶつ", "けんま", "けんみん", "けんめい", "けんらん", "けんり", "こあくま", "こいぬ", "こいびと", "ごうい", "こうえん", "こうおん", "こうかん", "ごうきゅう", "ごうけい", "こうこう", "こうさい", "こうじ", "こうすい", "ごうせい", "こうそく", "こうたい", "こうちゃ", "こうつう", "こうてい", "こうどう", "こうない", "こうはい", "ごうほう", "ごうまん", "こうもく", "こうりつ", "こえる", "こおり", "ごかい", "ごがつ", "ごかん", "こくご", "こくさい", "こくとう", "こくない", "こくはく", "こぐま", "こけい", "こける", "ここのか", "こころ", "こさめ", "こしつ", "こすう", "こせい", "こせき", "こぜん", "こそだて", "こたい", "こたえる", "こたつ", "こちょう", "こっか", "こつこつ", "こつばん", "こつぶ", "こてい", "こてん", "ことがら", "ことし", "ことば", "ことり", "こなごな", "こねこね", "このまま", "このみ", "このよ", "ごはん", "こひつじ", "こふう", "こふん", "こぼれる", "ごまあぶら", "こまかい", "ごますり", "こまつな", "こまる", "こむぎこ", "こもじ", "こもち", "こもの", "こもん", "こやく", "こやま", "こゆう", "こゆび", "こよい", "こよう", "こりる", "これくしょん", "ころっけ", "こわもて", "こわれる", "こんいん", "こんかい", "こんき", "こんしゅう", "こんすい", "こんだて", "こんとん", "こんなん", "こんびに", "こんぽん", "こんまけ", "こんや", "こんれい", "こんわく", "ざいえき", "さいかい", "さいきん", "ざいげん", "ざいこ", "さいしょ", "さいせい", "ざいたく", "ざいちゅう", "さいてき", "ざいりょう", "さうな", "さかいし", "さがす", "さかな", "さかみち", "さがる", "さぎょう", "さくし", "さくひん", "さくら", "さこく", "さこつ", "さずかる", "ざせき", "さたん", "さつえい", "ざつおん", "ざっか", "ざつがく", "さっきょく", "ざっし", "さつじん", "ざっそう", "さつたば", "さつまいも", "さてい", "さといも", "さとう", "さとおや", "さとし", "さとる", "さのう", "さばく", "さびしい", "さべつ", "さほう", "さほど", "さます", "さみしい", "さみだれ", "さむけ", "さめる", "さやえんどう", "さゆう", "さよう", "さよく", "さらだ", "ざるそば", "さわやか", "さわる", "さんいん", "さんか", "さんきゃく", "さんこう", "さんさい", "ざんしょ", "さんすう", "さんせい", "さんそ", "さんち", "さんま", "さんみ", "さんらん", "しあい", "しあげ", "しあさって", "しあわせ", "しいく", "しいん", "しうち", "しえい", "しおけ", "しかい", "しかく", "じかん", "しごと", "しすう", "じだい", "したうけ", "したぎ", "したて", "したみ", "しちょう", "しちりん", "しっかり", "しつじ", "しつもん", "してい", "してき", "してつ", "じてん", "じどう", "しなぎれ", "しなもの", "しなん", "しねま", "しねん", "しのぐ", "しのぶ", "しはい", "しばかり", "しはつ", "しはらい", "しはん", "しひょう", "しふく", "じぶん", "しへい", "しほう", "しほん", "しまう", "しまる", "しみん", "しむける", "じむしょ", "しめい", "しめる", "しもん", "しゃいん", "しゃうん", "しゃおん", "じゃがいも", "しやくしょ", "しゃくほう", "しゃけん", "しゃこ", "しゃざい", "しゃしん", "しゃせん", "しゃそう", "しゃたい", "しゃちょう", "しゃっきん", "じゃま", "しゃりん", "しゃれい", "じゆう", "じゅうしょ", "しゅくはく", "じゅしん", "しゅっせき", "しゅみ", "しゅらば", "じゅんばん", "しょうかい", "しょくたく", "しょっけん", "しょどう", "しょもつ", "しらせる", "しらべる", "しんか", "しんこう", "じんじゃ", "しんせいじ", "しんちく", "しんりん", "すあげ", "すあし", "すあな", "ずあん", "すいえい", "すいか", "すいとう", "ずいぶん", "すいようび", "すうがく", "すうじつ", "すうせん", "すおどり", "すきま", "すくう", "すくない", "すける", "すごい", "すこし", "ずさん", "すずしい", "すすむ", "すすめる", "すっかり", "ずっしり", "ずっと", "すてき", "すてる", "すねる", "すのこ", "すはだ", "すばらしい", "ずひょう", "ずぶぬれ", "すぶり", "すふれ", "すべて", "すべる", "ずほう", "すぼん", "すまい", "すめし", "すもう", "すやき", "すらすら", "するめ", "すれちがう", "すろっと", "すわる", "すんぜん", "すんぽう", "せあぶら", "せいかつ", "せいげん", "せいじ", "せいよう", "せおう", "せかいかん", "せきにん", "せきむ", "せきゆ", "せきらんうん", "せけん", "せこう", "せすじ", "せたい", "せたけ", "せっかく", "せっきゃく", "ぜっく", "せっけん", "せっこつ", "せっさたくま", "せつぞく", "せつだん", "せつでん", "せっぱん", "せつび", "せつぶん", "せつめい", "せつりつ", "せなか", "せのび", "せはば", "せびろ", "せぼね", "せまい", "せまる", "せめる", "せもたれ", "せりふ", "ぜんあく", "せんい", "せんえい", "せんか", "せんきょ", "せんく", "せんげん", "ぜんご", "せんさい", "せんしゅ", "せんすい", "せんせい", "せんぞ", "せんたく", "せんちょう", "せんてい", "せんとう", "せんぬき", "せんねん", "せんぱい", "ぜんぶ", "ぜんぽう", "せんむ", "せんめんじょ", "せんもん", "せんやく", "せんゆう", "せんよう", "ぜんら", "ぜんりゃく", "せんれい", "せんろ", "そあく", "そいとげる", "そいね", "そうがんきょう", "そうき", "そうご", "そうしん", "そうだん", "そうなん", "そうび", "そうめん", "そうり", "そえもの", "そえん", "そがい", "そげき", "そこう", "そこそこ", "そざい", "そしな", "そせい", "そせん", "そそぐ", "そだてる", "そつう", "そつえん", "そっかん", "そつぎょう", "そっけつ", "そっこう", "そっせん", "そっと", "そとがわ", "そとづら", "そなえる", "そなた", "そふぼ", "そぼく", "そぼろ", "そまつ", "そまる", "そむく", "そむりえ", "そめる", "そもそも", "そよかぜ", "そらまめ", "そろう", "そんかい", "そんけい", "そんざい", "そんしつ", "そんぞく", "そんちょう", "ぞんび", "ぞんぶん", "そんみん", "たあい", "たいいん", "たいうん", "たいえき", "たいおう", "だいがく", "たいき", "たいぐう", "たいけん", "たいこ", "たいざい", "だいじょうぶ", "だいすき", "たいせつ", "たいそう", "だいたい", "たいちょう", "たいてい", "だいどころ", "たいない", "たいねつ", "たいのう", "たいはん", "だいひょう", "たいふう", "たいへん", "たいほ", "たいまつばな", "たいみんぐ", "たいむ", "たいめん", "たいやき", "たいよう", "たいら", "たいりょく", "たいる", "たいわん", "たうえ", "たえる", "たおす", "たおる", "たおれる", "たかい", "たかね", "たきび", "たくさん", "たこく", "たこやき", "たさい", "たしざん", "だじゃれ", "たすける", "たずさわる", "たそがれ", "たたかう", "たたく", "ただしい", "たたみ", "たちばな", "だっかい", "だっきゃく", "だっこ", "だっしゅつ", "だったい", "たてる", "たとえる", "たなばた", "たにん", "たぬき", "たのしみ", "たはつ", "たぶん", "たべる", "たぼう", "たまご", "たまる", "だむる", "ためいき", "ためす", "ためる", "たもつ", "たやすい", "たよる", "たらす", "たりきほんがん", "たりょう", "たりる", "たると", "たれる", "たれんと", "たろっと", "たわむれる", "だんあつ", "たんい", "たんおん", "たんか", "たんき", "たんけん", "たんご", "たんさん", "たんじょうび", "だんせい", "たんそく", "たんたい", "だんち", "たんてい", "たんとう", "だんな", "たんにん", "だんねつ", "たんのう", "たんぴん", "だんぼう", "たんまつ", "たんめい", "だんれつ", "だんろ", "だんわ", "ちあい", "ちあん", "ちいき", "ちいさい", "ちえん", "ちかい", "ちから", "ちきゅう", "ちきん", "ちけいず", "ちけん", "ちこく", "ちさい", "ちしき", "ちしりょう", "ちせい", "ちそう", "ちたい", "ちたん", "ちちおや", "ちつじょ", "ちてき", "ちてん", "ちぬき", "ちぬり", "ちのう", "ちひょう", "ちへいせん", "ちほう", "ちまた", "ちみつ", "ちみどろ", "ちめいど", "ちゃんこなべ", "ちゅうい", "ちゆりょく", "ちょうし", "ちょさくけん", "ちらし", "ちらみ", "ちりがみ", "ちりょう", "ちるど", "ちわわ", "ちんたい", "ちんもく", "ついか", "ついたち", "つうか", "つうじょう", "つうはん", "つうわ", "つかう", "つかれる", "つくね", "つくる", "つけね", "つける", "つごう", "つたえる", "つづく", "つつじ", "つつむ", "つとめる", "つながる", "つなみ", "つねづね", "つのる", "つぶす", "つまらない", "つまる", "つみき", "つめたい", "つもり", "つもる", "つよい", "つるぼ", "つるみく", "つわもの", "つわり", "てあし", "てあて", "てあみ", "ていおん", "ていか", "ていき", "ていけい", "ていこく", "ていさつ", "ていし", "ていせい", "ていたい", "ていど", "ていねい", "ていひょう", "ていへん", "ていぼう", "てうち", "ておくれ", "てきとう", "てくび", "でこぼこ", "てさぎょう", "てさげ", "てすり", "てそう", "てちがい", "てちょう", "てつがく", "てつづき", "でっぱ", "てつぼう", "てつや", "でぬかえ", "てぬき", "てぬぐい", "てのひら", "てはい", "てぶくろ", "てふだ", "てほどき", "てほん", "てまえ", "てまきずし", "てみじか", "てみやげ", "てらす", "てれび", "てわけ", "てわたし", "でんあつ", "てんいん", "てんかい", "てんき", "てんぐ", "てんけん", "てんごく", "てんさい", "てんし", "てんすう", "でんち", "てんてき", "てんとう", "てんない", "てんぷら", "てんぼうだい", "てんめつ", "てんらんかい", "でんりょく", "でんわ", "どあい", "といれ", "どうかん", "とうきゅう", "どうぐ", "とうし", "とうむぎ", "とおい", "とおか", "とおく", "とおす", "とおる", "とかい", "とかす", "ときおり", "ときどき", "とくい", "とくしゅう", "とくてん", "とくに", "とくべつ", "とけい", "とける", "とこや", "とさか", "としょかん", "とそう", "とたん", "とちゅう", "とっきゅう", "とっくん", "とつぜん", "とつにゅう", "とどける", "ととのえる", "とない", "となえる", "となり", "とのさま", "とばす", "どぶがわ", "とほう", "とまる", "とめる", "ともだち", "ともる", "どようび", "とらえる", "とんかつ", "どんぶり", "ないかく", "ないこう", "ないしょ", "ないす", "ないせん", "ないそう", "なおす", "ながい", "なくす", "なげる", "なこうど", "なさけ", "なたでここ", "なっとう", "なつやすみ", "ななおし", "なにごと", "なにもの", "なにわ", "なのか", "なふだ", "なまいき", "なまえ", "なまみ", "なみだ", "なめらか", "なめる", "なやむ", "ならう", "ならび", "ならぶ", "なれる", "なわとび", "なわばり", "にあう", "にいがた", "にうけ", "におい", "にかい", "にがて", "にきび", "にくしみ", "にくまん", "にげる", "にさんかたんそ", "にしき", "にせもの", "にちじょう", "にちようび", "にっか", "にっき", "にっけい", "にっこう", "にっさん", "にっしょく", "にっすう", "にっせき", "にってい", "になう", "にほん", "にまめ", "にもつ", "にやり", "にゅういん", "にりんしゃ", "にわとり", "にんい", "にんか", "にんき", "にんげん", "にんしき", "にんずう", "にんそう", "にんたい", "にんち", "にんてい", "にんにく", "にんぷ", "にんまり", "にんむ", "にんめい", "にんよう", "ぬいくぎ", "ぬかす", "ぬぐいとる", "ぬぐう", "ぬくもり", "ぬすむ", "ぬまえび", "ぬめり", "ぬらす", "ぬんちゃく", "ねあげ", "ねいき", "ねいる", "ねいろ", "ねぐせ", "ねくたい", "ねくら", "ねこぜ", "ねこむ", "ねさげ", "ねすごす", "ねそべる", "ねだん", "ねつい", "ねっしん", "ねつぞう", "ねったいぎょ", "ねぶそく", "ねふだ", "ねぼう", "ねほりはほり", "ねまき", "ねまわし", "ねみみ", "ねむい", "ねむたい", "ねもと", "ねらう", "ねわざ", "ねんいり", "ねんおし", "ねんかん", "ねんきん", "ねんぐ", "ねんざ", "ねんし", "ねんちゃく", "ねんど", "ねんぴ", "ねんぶつ", "ねんまつ", "ねんりょう", "ねんれい", "のいず", "のおづま", "のがす", "のきなみ", "のこぎり", "のこす", "のこる", "のせる", "のぞく", "のぞむ", "のたまう", "のちほど", "のっく", "のばす", "のはら", "のべる", "のぼる", "のみもの", "のやま", "のらいぬ", "のらねこ", "のりもの", "のりゆき", "のれん", "のんき", "ばあい", "はあく", "ばあさん", "ばいか", "ばいく", "はいけん", "はいご", "はいしん", "はいすい", "はいせん", "はいそう", "はいち", "ばいばい", "はいれつ", "はえる", "はおる", "はかい", "ばかり", "はかる", "はくしゅ", "はけん", "はこぶ", "はさみ", "はさん", "はしご", "ばしょ", "はしる", "はせる", "ぱそこん", "はそん", "はたん", "はちみつ", "はつおん", "はっかく", "はづき", "はっきり", "はっくつ", "はっけん", "はっこう", "はっさん", "はっしん", "はったつ", "はっちゅう", "はってん", "はっぴょう", "はっぽう", "はなす", "はなび", "はにかむ", "はぶらし", "はみがき", "はむかう", "はめつ", "はやい", "はやし", "はらう", "はろうぃん", "はわい", "はんい", "はんえい", "はんおん", "はんかく", "はんきょう", "ばんぐみ", "はんこ", "はんしゃ", "はんすう", "はんだん", "ぱんち", "ぱんつ", "はんてい", "はんとし", "はんのう", "はんぱ", "はんぶん", "はんぺん", "はんぼうき", "はんめい", "はんらん", "はんろん", "ひいき", "ひうん", "ひえる", "ひかく", "ひかり", "ひかる", "ひかん", "ひくい", "ひけつ", "ひこうき", "ひこく", "ひさい", "ひさしぶり", "ひさん", "びじゅつかん", "ひしょ", "ひそか", "ひそむ", "ひたむき", "ひだり", "ひたる", "ひつぎ", "ひっこし", "ひっし", "ひつじゅひん", "ひっす", "ひつぜん", "ぴったり", "ぴっちり", "ひつよう", "ひてい", "ひとごみ", "ひなまつり", "ひなん", "ひねる", "ひはん", "ひびく", "ひひょう", "ひほう", "ひまわり", "ひまん", "ひみつ", "ひめい", "ひめじし", "ひやけ", "ひやす", "ひよう", "びょうき", "ひらがな", "ひらく", "ひりつ", "ひりょう", "ひるま", "ひるやすみ", "ひれい", "ひろい", "ひろう", "ひろき", "ひろゆき", "ひんかく", "ひんけつ", "ひんこん", "ひんしゅ", "ひんそう", "ぴんち", "ひんぱん", "びんぼう", "ふあん", "ふいうち", "ふうけい", "ふうせん", "ぷうたろう", "ふうとう", "ふうふ", "ふえる", "ふおん", "ふかい", "ふきん", "ふくざつ", "ふくぶくろ", "ふこう", "ふさい", "ふしぎ", "ふじみ", "ふすま", "ふせい", "ふせぐ", "ふそく", "ぶたにく", "ふたん", "ふちょう", "ふつう", "ふつか", "ふっかつ", "ふっき", "ふっこく", "ぶどう", "ふとる", "ふとん", "ふのう", "ふはい", "ふひょう", "ふへん", "ふまん", "ふみん", "ふめつ", "ふめん", "ふよう", "ふりこ", "ふりる", "ふるい", "ふんいき", "ぶんがく", "ぶんぐ", "ふんしつ", "ぶんせき", "ふんそう", "ぶんぽう", "へいあん", "へいおん", "へいがい", "へいき", "へいげん", "へいこう", "へいさ", "へいしゃ", "へいせつ", "へいそ", "へいたく", "へいてん", "へいねつ", "へいわ", "へきが", "へこむ", "べにいろ", "べにしょうが", "へらす", "へんかん", "べんきょう", "べんごし", "へんさい", "へんたい", "べんり", "ほあん", "ほいく", "ぼうぎょ", "ほうこく", "ほうそう", "ほうほう", "ほうもん", "ほうりつ", "ほえる", "ほおん", "ほかん", "ほきょう", "ぼきん", "ほくろ", "ほけつ", "ほけん", "ほこう", "ほこる", "ほしい", "ほしつ", "ほしゅ", "ほしょう", "ほせい", "ほそい", "ほそく", "ほたて", "ほたる", "ぽちぶくろ", "ほっきょく", "ほっさ", "ほったん", "ほとんど", "ほめる", "ほんい", "ほんき", "ほんけ", "ほんしつ", "ほんやく", "まいにち", "まかい", "まかせる", "まがる", "まける", "まこと", "まさつ", "まじめ", "ますく", "まぜる", "まつり", "まとめ", "まなぶ", "まぬけ", "まねく", "まほう", "まもる", "まゆげ", "まよう", "まろやか", "まわす", "まわり", "まわる", "まんが", "まんきつ", "まんぞく", "まんなか", "みいら", "みうち", "みえる", "みがく", "みかた", "みかん", "みけん", "みこん", "みじかい", "みすい", "みすえる", "みせる", "みっか", "みつかる", "みつける", "みてい", "みとめる", "みなと", "みなみかさい", "みねらる", "みのう", "みのがす", "みほん", "みもと", "みやげ", "みらい", "みりょく", "みわく", "みんか", "みんぞく", "むいか", "むえき", "むえん", "むかい", "むかう", "むかえ", "むかし", "むぎちゃ", "むける", "むげん", "むさぼる", "むしあつい", "むしば", "むじゅん", "むしろ", "むすう", "むすこ", "むすぶ", "むすめ", "むせる", "むせん", "むちゅう", "むなしい", "むのう", "むやみ", "むよう", "むらさき", "むりょう", "むろん", "めいあん", "めいうん", "めいえん", "めいかく", "めいきょく", "めいさい", "めいし", "めいそう", "めいぶつ", "めいれい", "めいわく", "めぐまれる", "めざす", "めした", "めずらしい", "めだつ", "めまい", "めやす", "めんきょ", "めんせき", "めんどう", "もうしあげる", "もうどうけん", "もえる", "もくし", "もくてき", "もくようび", "もちろん", "もどる", "もらう", "もんく", "もんだい", "やおや", "やける", "やさい", "やさしい", "やすい", "やすたろう", "やすみ", "やせる", "やそう", "やたい", "やちん", "やっと", "やっぱり", "やぶる", "やめる", "ややこしい", "やよい", "やわらかい", "ゆうき", "ゆうびんきょく", "ゆうべ", "ゆうめい", "ゆけつ", "ゆしゅつ", "ゆせん", "ゆそう", "ゆたか", "ゆちゃく", "ゆでる", "ゆにゅう", "ゆびわ", "ゆらい", "ゆれる", "ようい", "ようか", "ようきゅう", "ようじ", "ようす", "ようちえん", "よかぜ", "よかん", "よきん", "よくせい", "よくぼう", "よけい", "よごれる", "よさん", "よしゅう", "よそう", "よそく", "よっか", "よてい", "よどがわく", "よねつ", "よやく", "よゆう", "よろこぶ", "よろしい", "らいう", "らくがき", "らくご", "らくさつ", "らくだ", "らしんばん", "らせん", "らぞく", "らたい", "らっか", "られつ", "りえき", "りかい", "りきさく", "りきせつ", "りくぐん", "りくつ", "りけん", "りこう", "りせい", "りそう", "りそく", "りてん", "りねん", "りゆう", "りゅうがく", "りよう", "りょうり", "りょかん", "りょくちゃ", "りょこう", "りりく", "りれき", "りろん", "りんご", "るいけい", "るいさい", "るいじ", "るいせき", "るすばん", "るりがわら", "れいかん", "れいぎ", "れいせい", "れいぞうこ", "れいとう", "れいぼう", "れきし", "れきだい", "れんあい", "れんけい", "れんこん", "れんさい", "れんしゅう", "れんぞく", "れんらく", "ろうか", "ろうご", "ろうじん", "ろうそく", "ろくが", "ろこつ", "ろじうら", "ろしゅつ", "ろせん", "ろてん", "ろめん", "ろれつ", "ろんぎ", "ろんぱ", "ろんぶん", "ろんり", "わかす", "わかめ", "わかやま", "わかれる", "わしつ", "わじまし", "わすれもの", "わらう", "われる"] static var koreanWords: [String] = ["가격", "가끔", "가난", "가능", "가득", "가르침", "가뭄", "가방", "가상", "가슴", "가운데", "가을", "가이드", "가입", "가장", "가정", "가족", "가죽", "각오", "각자", "간격", "간부", "간섭", "간장", "간접", "간판", "갈등", "갈비", "갈색", "갈증", "감각", "감기", "감소", "감수성", "감자", "감정", "갑자기", "강남", "강당", "강도", "강력히", "강변", "강북", "강사", "강수량", "강아지", "강원도", "강의", "강제", "강조", "같이", "개구리", "개나리", "개방", "개별", "개선", "개성", "개인", "객관적", "거실", "거액", "거울", "거짓", "거품", "걱정", "건강", "건물", "건설", "건조", "건축", "걸음", "검사", "검토", "게시판", "게임", "겨울", "견해", "결과", "결국", "결론", "결석", "결승", "결심", "결정", "결혼", "경계", "경고", "경기", "경력", "경복궁", "경비", "경상도", "경영", "경우", "경쟁", "경제", "경주", "경찰", "경치", "경향", "경험", "계곡", "계단", "계란", "계산", "계속", "계약", "계절", "계층", "계획", "고객", "고구려", "고궁", "고급", "고등학생", "고무신", "고민", "고양이", "고장", "고전", "고집", "고춧가루", "고통", "고향", "곡식", "골목", "골짜기", "골프", "공간", "공개", "공격", "공군", "공급", "공기", "공동", "공무원", "공부", "공사", "공식", "공업", "공연", "공원", "공장", "공짜", "공책", "공통", "공포", "공항", "공휴일", "과목", "과일", "과장", "과정", "과학", "관객", "관계", "관광", "관념", "관람", "관련", "관리", "관습", "관심", "관점", "관찰", "광경", "광고", "광장", "광주", "괴로움", "굉장히", "교과서", "교문", "교복", "교실", "교양", "교육", "교장", "교직", "교통", "교환", "교훈", "구경", "구름", "구멍", "구별", "구분", "구석", "구성", "구속", "구역", "구입", "구청", "구체적", "국가", "국기", "국내", "국립", "국물", "국민", "국수", "국어", "국왕", "국적", "국제", "국회", "군대", "군사", "군인", "궁극적", "권리", "권위", "권투", "귀국", "귀신", "규정", "규칙", "균형", "그날", "그냥", "그늘", "그러나", "그룹", "그릇", "그림", "그제서야", "그토록", "극복", "극히", "근거", "근교", "근래", "근로", "근무", "근본", "근원", "근육", "근처", "글씨", "글자", "금강산", "금고", "금년", "금메달", "금액", "금연", "금요일", "금지", "긍정적", "기간", "기관", "기념", "기능", "기독교", "기둥", "기록", "기름", "기법", "기본", "기분", "기쁨", "기숙사", "기술", "기억", "기업", "기온", "기운", "기원", "기적", "기준", "기침", "기혼", "기획", "긴급", "긴장", "길이", "김밥", "김치", "김포공항", "깍두기", "깜빡", "깨달음", "깨소금", "껍질", "꼭대기", "꽃잎", "나들이", "나란히", "나머지", "나물", "나침반", "나흘", "낙엽", "난방", "날개", "날씨", "날짜", "남녀", "남대문", "남매", "남산", "남자", "남편", "남학생", "낭비", "낱말", "내년", "내용", "내일", "냄비", "냄새", "냇물", "냉동", "냉면", "냉방", "냉장고", "넥타이", "넷째", "노동", "노란색", "노력", "노인", "녹음", "녹차", "녹화", "논리", "논문", "논쟁", "놀이", "농구", "농담", "농민", "농부", "농업", "농장", "농촌", "높이", "눈동자", "눈물", "눈썹", "뉴욕", "느낌", "늑대", "능동적", "능력", "다방", "다양성", "다음", "다이어트", "다행", "단계", "단골", "단독", "단맛", "단순", "단어", "단위", "단점", "단체", "단추", "단편", "단풍", "달걀", "달러", "달력", "달리", "닭고기", "담당", "담배", "담요", "담임", "답변", "답장", "당근", "당분간", "당연히", "당장", "대규모", "대낮", "대단히", "대답", "대도시", "대략", "대량", "대륙", "대문", "대부분", "대신", "대응", "대장", "대전", "대접", "대중", "대책", "대출", "대충", "대통령", "대학", "대한민국", "대합실", "대형", "덩어리", "데이트", "도대체", "도덕", "도둑", "도망", "도서관", "도심", "도움", "도입", "도자기", "도저히", "도전", "도중", "도착", "독감", "독립", "독서", "독일", "독창적", "동화책", "뒷모습", "뒷산", "딸아이", "마누라", "마늘", "마당", "마라톤", "마련", "마무리", "마사지", "마약", "마요네즈", "마을", "마음", "마이크", "마중", "마지막", "마찬가지", "마찰", "마흔", "막걸리", "막내", "막상", "만남", "만두", "만세", "만약", "만일", "만점", "만족", "만화", "많이", "말기", "말씀", "말투", "맘대로", "망원경", "매년", "매달", "매력", "매번", "매스컴", "매일", "매장", "맥주", "먹이", "먼저", "먼지", "멀리", "메일", "며느리", "며칠", "면담", "멸치", "명단", "명령", "명예", "명의", "명절", "명칭", "명함", "모금", "모니터", "모델", "모든", "모범", "모습", "모양", "모임", "모조리", "모집", "모퉁이", "목걸이", "목록", "목사", "목소리", "목숨", "목적", "목표", "몰래", "몸매", "몸무게", "몸살", "몸속", "몸짓", "몸통", "몹시", "무관심", "무궁화", "무더위", "무덤", "무릎", "무슨", "무엇", "무역", "무용", "무조건", "무지개", "무척", "문구", "문득", "문법", "문서", "문제", "문학", "문화", "물가", "물건", "물결", "물고기", "물론", "물리학", "물음", "물질", "물체", "미국", "미디어", "미사일", "미술", "미역", "미용실", "미움", "미인", "미팅", "미혼", "민간", "민족", "민주", "믿음", "밀가루", "밀리미터", "밑바닥", "바가지", "바구니", "바나나", "바늘", "바닥", "바닷가", "바람", "바이러스", "바탕", "박물관", "박사", "박수", "반대", "반드시", "반말", "반발", "반성", "반응", "반장", "반죽", "반지", "반찬", "받침", "발가락", "발걸음", "발견", "발달", "발레", "발목", "발바닥", "발생", "발음", "발자국", "발전", "발톱", "발표", "밤하늘", "밥그릇", "밥맛", "밥상", "밥솥", "방금", "방면", "방문", "방바닥", "방법", "방송", "방식", "방안", "방울", "방지", "방학", "방해", "방향", "배경", "배꼽", "배달", "배드민턴", "백두산", "백색", "백성", "백인", "백제", "백화점", "버릇", "버섯", "버튼", "번개", "번역", "번지", "번호", "벌금", "벌레", "벌써", "범위", "범인", "범죄", "법률", "법원", "법적", "법칙", "베이징", "벨트", "변경", "변동", "변명", "변신", "변호사", "변화", "별도", "별명", "별일", "병실", "병아리", "병원", "보관", "보너스", "보라색", "보람", "보름", "보상", "보안", "보자기", "보장", "보전", "보존", "보통", "보편적", "보험", "복도", "복사", "복숭아", "복습", "볶음", "본격적", "본래", "본부", "본사", "본성", "본인", "본질", "볼펜", "봉사", "봉지", "봉투", "부근", "부끄러움", "부담", "부동산", "부문", "부분", "부산", "부상", "부엌", "부인", "부작용", "부장", "부정", "부족", "부지런히", "부친", "부탁", "부품", "부회장", "북부", "북한", "분노", "분량", "분리", "분명", "분석", "분야", "분위기", "분필", "분홍색", "불고기", "불과", "불교", "불꽃", "불만", "불법", "불빛", "불안", "불이익", "불행", "브랜드", "비극", "비난", "비닐", "비둘기", "비디오", "비로소", "비만", "비명", "비밀", "비바람", "비빔밥", "비상", "비용", "비율", "비중", "비타민", "비판", "빌딩", "빗물", "빗방울", "빗줄기", "빛깔", "빨간색", "빨래", "빨리", "사건", "사계절", "사나이", "사냥", "사람", "사랑", "사립", "사모님", "사물", "사방", "사상", "사생활", "사설", "사슴", "사실", "사업", "사용", "사월", "사장", "사전", "사진", "사촌", "사춘기", "사탕", "사투리", "사흘", "산길", "산부인과", "산업", "산책", "살림", "살인", "살짝", "삼계탕", "삼국", "삼십", "삼월", "삼촌", "상관", "상금", "상대", "상류", "상반기", "상상", "상식", "상업", "상인", "상자", "상점", "상처", "상추", "상태", "상표", "상품", "상황", "새벽", "색깔", "색연필", "생각", "생명", "생물", "생방송", "생산", "생선", "생신", "생일", "생활", "서랍", "서른", "서명", "서민", "서비스", "서양", "서울", "서적", "서점", "서쪽", "서클", "석사", "석유", "선거", "선물", "선배", "선생", "선수", "선원", "선장", "선전", "선택", "선풍기", "설거지", "설날", "설렁탕", "설명", "설문", "설사", "설악산", "설치", "설탕", "섭씨", "성공", "성당", "성명", "성별", "성인", "성장", "성적", "성질", "성함", "세금", "세미나", "세상", "세월", "세종대왕", "세탁", "센터", "센티미터", "셋째", "소규모", "소극적", "소금", "소나기", "소년", "소득", "소망", "소문", "소설", "소속", "소아과", "소용", "소원", "소음", "소중히", "소지품", "소질", "소풍", "소형", "속담", "속도", "속옷", "손가락", "손길", "손녀", "손님", "손등", "손목", "손뼉", "손실", "손질", "손톱", "손해", "솔직히", "솜씨", "송아지", "송이", "송편", "쇠고기", "쇼핑", "수건", "수년", "수단", "수돗물", "수동적", "수면", "수명", "수박", "수상", "수석", "수술", "수시로", "수업", "수염", "수영", "수입", "수준", "수집", "수출", "수컷", "수필", "수학", "수험생", "수화기", "숙녀", "숙소", "숙제", "순간", "순서", "순수", "순식간", "순위", "숟가락", "술병", "술집", "숫자", "스님", "스물", "스스로", "스승", "스웨터", "스위치", "스케이트", "스튜디오", "스트레스", "스포츠", "슬쩍", "슬픔", "습관", "습기", "승객", "승리", "승부", "승용차", "승진", "시각", "시간", "시골", "시금치", "시나리오", "시댁", "시리즈", "시멘트", "시민", "시부모", "시선", "시설", "시스템", "시아버지", "시어머니", "시월", "시인", "시일", "시작", "시장", "시절", "시점", "시중", "시즌", "시집", "시청", "시합", "시험", "식구", "식기", "식당", "식량", "식료품", "식물", "식빵", "식사", "식생활", "식초", "식탁", "식품", "신고", "신규", "신념", "신문", "신발", "신비", "신사", "신세", "신용", "신제품", "신청", "신체", "신화", "실감", "실내", "실력", "실례", "실망", "실수", "실습", "실시", "실장", "실정", "실질적", "실천", "실체", "실컷", "실태", "실패", "실험", "실현", "심리", "심부름", "심사", "심장", "심정", "심판", "쌍둥이", "씨름", "씨앗", "아가씨", "아나운서", "아드님", "아들", "아쉬움", "아스팔트", "아시아", "아울러", "아저씨", "아줌마", "아직", "아침", "아파트", "아프리카", "아픔", "아홉", "아흔", "악기", "악몽", "악수", "안개", "안경", "안과", "안내", "안녕", "안동", "안방", "안부", "안주", "알루미늄", "알코올", "암시", "암컷", "압력", "앞날", "앞문", "애인", "애정", "액수", "앨범", "야간", "야단", "야옹", "약간", "약국", "약속", "약수", "약점", "약품", "약혼녀", "양념", "양력", "양말", "양배추", "양주", "양파", "어둠", "어려움", "어른", "어젯밤", "어쨌든", "어쩌다가", "어쩐지", "언니", "언덕", "언론", "언어", "얼굴", "얼른", "얼음", "얼핏", "엄마", "업무", "업종", "업체", "엉덩이", "엉망", "엉터리", "엊그제", "에너지", "에어컨", "엔진", "여건", "여고생", "여관", "여군", "여권", "여대생", "여덟", "여동생", "여든", "여론", "여름", "여섯", "여성", "여왕", "여인", "여전히", "여직원", "여학생", "여행", "역사", "역시", "역할", "연결", "연구", "연극", "연기", "연락", "연설", "연세", "연속", "연습", "연애", "연예인", "연인", "연장", "연주", "연출", "연필", "연합", "연휴", "열기", "열매", "열쇠", "열심히", "열정", "열차", "열흘", "염려", "엽서", "영국", "영남", "영상", "영양", "영역", "영웅", "영원히", "영하", "영향", "영혼", "영화", "옆구리", "옆방", "옆집", "예감", "예금", "예방", "예산", "예상", "예선", "예술", "예습", "예식장", "예약", "예전", "예절", "예정", "예컨대", "옛날", "오늘", "오락", "오랫동안", "오렌지", "오로지", "오른발", "오븐", "오십", "오염", "오월", "오전", "오직", "오징어", "오페라", "오피스텔", "오히려", "옥상", "옥수수", "온갖", "온라인", "온몸", "온종일", "온통", "올가을", "올림픽", "올해", "옷차림", "와이셔츠", "와인", "완성", "완전", "왕비", "왕자", "왜냐하면", "왠지", "외갓집", "외국", "외로움", "외삼촌", "외출", "외침", "외할머니", "왼발", "왼손", "왼쪽", "요금", "요일", "요즘", "요청", "용기", "용서", "용어", "우산", "우선", "우승", "우연히", "우정", "우체국", "우편", "운동", "운명", "운반", "운전", "운행", "울산", "울음", "움직임", "웃어른", "웃음", "워낙", "원고", "원래", "원서", "원숭이", "원인", "원장", "원피스", "월급", "월드컵", "월세", "월요일", "웨이터", "위반", "위법", "위성", "위원", "위험", "위협", "윗사람", "유난히", "유럽", "유명", "유물", "유산", "유적", "유치원", "유학", "유행", "유형", "육군", "육상", "육십", "육체", "은행", "음력", "음료", "음반", "음성", "음식", "음악", "음주", "의견", "의논", "의문", "의복", "의식", "의심", "의외로", "의욕", "의원", "의학", "이것", "이곳", "이념", "이놈", "이달", "이대로", "이동", "이렇게", "이력서", "이론적", "이름", "이민", "이발소", "이별", "이불", "이빨", "이상", "이성", "이슬", "이야기", "이용", "이웃", "이월", "이윽고", "이익", "이전", "이중", "이튿날", "이틀", "이혼", "인간", "인격", "인공", "인구", "인근", "인기", "인도", "인류", "인물", "인생", "인쇄", "인연", "인원", "인재", "인종", "인천", "인체", "인터넷", "인하", "인형", "일곱", "일기", "일단", "일대", "일등", "일반", "일본", "일부", "일상", "일생", "일손", "일요일", "일월", "일정", "일종", "일주일", "일찍", "일체", "일치", "일행", "일회용", "임금", "임무", "입대", "입력", "입맛", "입사", "입술", "입시", "입원", "입장", "입학", "자가용", "자격", "자극", "자동", "자랑", "자부심", "자식", "자신", "자연", "자원", "자율", "자전거", "자정", "자존심", "자판", "작가", "작년", "작성", "작업", "작용", "작은딸", "작품", "잔디", "잔뜩", "잔치", "잘못", "잠깐", "잠수함", "잠시", "잠옷", "잠자리", "잡지", "장관", "장군", "장기간", "장래", "장례", "장르", "장마", "장면", "장모", "장미", "장비", "장사", "장소", "장식", "장애인", "장인", "장점", "장차", "장학금", "재능", "재빨리", "재산", "재생", "재작년", "재정", "재채기", "재판", "재학", "재활용", "저것", "저고리", "저곳", "저녁", "저런", "저렇게", "저번", "저울", "저절로", "저축", "적극", "적당히", "적성", "적용", "적응", "전개", "전공", "전기", "전달", "전라도", "전망", "전문", "전반", "전부", "전세", "전시", "전용", "전자", "전쟁", "전주", "전철", "전체", "전통", "전혀", "전후", "절대", "절망", "절반", "절약", "절차", "점검", "점수", "점심", "점원", "점점", "점차", "접근", "접시", "접촉", "젓가락", "정거장", "정도", "정류장", "정리", "정말", "정면", "정문", "정반대", "정보", "정부", "정비", "정상", "정성", "정오", "정원", "정장", "정지", "정치", "정확히", "제공", "제과점", "제대로", "제목", "제발", "제법", "제삿날", "제안", "제일", "제작", "제주도", "제출", "제품", "제한", "조각", "조건", "조금", "조깅", "조명", "조미료", "조상", "조선", "조용히", "조절", "조정", "조직", "존댓말", "존재", "졸업", "졸음", "종교", "종로", "종류", "종소리", "종업원", "종종", "종합", "좌석", "죄인", "주관적", "주름", "주말", "주머니", "주먹", "주문", "주민", "주방", "주변", "주식", "주인", "주일", "주장", "주전자", "주택", "준비", "줄거리", "줄기", "줄무늬", "중간", "중계방송", "중국", "중년", "중단", "중독", "중반", "중부", "중세", "중소기업", "중순", "중앙", "중요", "중학교", "즉석", "즉시", "즐거움", "증가", "증거", "증권", "증상", "증세", "지각", "지갑", "지경", "지극히", "지금", "지급", "지능", "지름길", "지리산", "지방", "지붕", "지식", "지역", "지우개", "지원", "지적", "지점", "지진", "지출", "직선", "직업", "직원", "직장", "진급", "진동", "진로", "진료", "진리", "진짜", "진찰", "진출", "진통", "진행", "질문", "질병", "질서", "짐작", "집단", "집안", "집중", "짜증", "찌꺼기", "차남", "차라리", "차량", "차림", "차별", "차선", "차츰", "착각", "찬물", "찬성", "참가", "참기름", "참새", "참석", "참여", "참외", "참조", "찻잔", "창가", "창고", "창구", "창문", "창밖", "창작", "창조", "채널", "채점", "책가방", "책방", "책상", "책임", "챔피언", "처벌", "처음", "천국", "천둥", "천장", "천재", "천천히", "철도", "철저히", "철학", "첫날", "첫째", "청년", "청바지", "청소", "청춘", "체계", "체력", "체온", "체육", "체중", "체험", "초등학생", "초반", "초밥", "초상화", "초순", "초여름", "초원", "초저녁", "초점", "초청", "초콜릿", "촛불", "총각", "총리", "총장", "촬영", "최근", "최상", "최선", "최신", "최악", "최종", "추석", "추억", "추진", "추천", "추측", "축구", "축소", "축제", "축하", "출근", "출발", "출산", "출신", "출연", "출입", "출장", "출판", "충격", "충고", "충돌", "충분히", "충청도", "취업", "취직", "취향", "치약", "친구", "친척", "칠십", "칠월", "칠판", "침대", "침묵", "침실", "칫솔", "칭찬", "카메라", "카운터", "칼국수", "캐릭터", "캠퍼스", "캠페인", "커튼", "컨디션", "컬러", "컴퓨터", "코끼리", "코미디", "콘서트", "콜라", "콤플렉스", "콩나물", "쾌감", "쿠데타", "크림", "큰길", "큰딸", "큰소리", "큰아들", "큰어머니", "큰일", "큰절", "클래식", "클럽", "킬로", "타입", "타자기", "탁구", "탁자", "탄생", "태권도", "태양", "태풍", "택시", "탤런트", "터널", "터미널", "테니스", "테스트", "테이블", "텔레비전", "토론", "토마토", "토요일", "통계", "통과", "통로", "통신", "통역", "통일", "통장", "통제", "통증", "통합", "통화", "퇴근", "퇴원", "퇴직금", "튀김", "트럭", "특급", "특별", "특성", "특수", "특징", "특히", "튼튼히", "티셔츠", "파란색", "파일", "파출소", "판결", "판단", "판매", "판사", "팔십", "팔월", "팝송", "패션", "팩스", "팩시밀리", "팬티", "퍼센트", "페인트", "편견", "편의", "편지", "편히", "평가", "평균", "평생", "평소", "평양", "평일", "평화", "포스터", "포인트", "포장", "포함", "표면", "표정", "표준", "표현", "품목", "품질", "풍경", "풍속", "풍습", "프랑스", "프린터", "플라스틱", "피곤", "피망", "피아노", "필름", "필수", "필요", "필자", "필통", "핑계", "하느님", "하늘", "하드웨어", "하룻밤", "하반기", "하숙집", "하순", "하여튼", "하지만", "하천", "하품", "하필", "학과", "학교", "학급", "학기", "학년", "학력", "학번", "학부모", "학비", "학생", "학술", "학습", "학용품", "학원", "학위", "학자", "학점", "한계", "한글", "한꺼번에", "한낮", "한눈", "한동안", "한때", "한라산", "한마디", "한문", "한번", "한복", "한식", "한여름", "한쪽", "할머니", "할아버지", "할인", "함께", "함부로", "합격", "합리적", "항공", "항구", "항상", "항의", "해결", "해군", "해답", "해당", "해물", "해석", "해설", "해수욕장", "해안", "핵심", "핸드백", "햄버거", "햇볕", "햇살", "행동", "행복", "행사", "행운", "행위", "향기", "향상", "향수", "허락", "허용", "헬기", "현관", "현금", "현대", "현상", "현실", "현장", "현재", "현지", "혈액", "협력", "형부", "형사", "형수", "형식", "형제", "형태", "형편", "혜택", "호기심", "호남", "호랑이", "호박", "호텔", "호흡", "혹시", "홀로", "홈페이지", "홍보", "홍수", "홍차", "화면", "화분", "화살", "화요일", "화장", "화학", "확보", "확인", "확장", "확정", "환갑", "환경", "환영", "환율", "환자", "활기", "활동", "활발히", "활용", "활짝", "회견", "회관", "회복", "회색", "회원", "회장", "회전", "횟수", "횡단보도", "효율적", "후반", "후춧가루", "훈련", "훨씬", "휴식", "휴일", "흉내", "흐름", "흑백", "흑인", "흔적", "흔히", "흥미", "흥분", "희곡", "희망", "희생", "흰색", "힘껏"] static var spanishWords: [String] = ["ábaco", "abdomen", "abeja", "abierto", "abogado", "abono", "aborto", "abrazo", "abrir", "abuelo", "abuso", "acabar", "academia", "acceso", "acción", "aceite", "acelga", "acento", "aceptar", "ácido", "aclarar", "acné", "acoger", "acoso", "activo", "acto", "actriz", "actuar", "acudir", "acuerdo", "acusar", "adicto", "admitir", "adoptar", "adorno", "aduana", "adulto", "aéreo", "afectar", "afición", "afinar", "afirmar", "ágil", "agitar", "agonía", "agosto", "agotar", "agregar", "agrio", "agua", "agudo", "águila", "aguja", "ahogo", "ahorro", "aire", "aislar", "ajedrez", "ajeno", "ajuste", "alacrán", "alambre", "alarma", "alba", "álbum", "alcalde", "aldea", "alegre", "alejar", "alerta", "aleta", "alfiler", "alga", "algodón", "aliado", "aliento", "alivio", "alma", "almeja", "almíbar", "altar", "alteza", "altivo", "alto", "altura", "alumno", "alzar", "amable", "amante", "amapola", "amargo", "amasar", "ámbar", "ámbito", "ameno", "amigo", "amistad", "amor", "amparo", "amplio", "ancho", "anciano", "ancla", "andar", "andén", "anemia", "ángulo", "anillo", "ánimo", "anís", "anotar", "antena", "antiguo", "antojo", "anual", "anular", "anuncio", "añadir", "añejo", "año", "apagar", "aparato", "apetito", "apio", "aplicar", "apodo", "aporte", "apoyo", "aprender", "aprobar", "apuesta", "apuro", "arado", "araña", "arar", "árbitro", "árbol", "arbusto", "archivo", "arco", "arder", "ardilla", "arduo", "área", "árido", "aries", "armonía", "arnés", "aroma", "arpa", "arpón", "arreglo", "arroz", "arruga", "arte", "artista", "asa", "asado", "asalto", "ascenso", "asegurar", "aseo", "asesor", "asiento", "asilo", "asistir", "asno", "asombro", "áspero", "astilla", "astro", "astuto", "asumir", "asunto", "atajo", "ataque", "atar", "atento", "ateo", "ático", "atleta", "átomo", "atraer", "atroz", "atún", "audaz", "audio", "auge", "aula", "aumento", "ausente", "autor", "aval", "avance", "avaro", "ave", "avellana", "avena", "avestruz", "avión", "aviso", "ayer", "ayuda", "ayuno", "azafrán", "azar", "azote", "azúcar", "azufre", "azul", "baba", "babor", "bache", "bahía", "baile", "bajar", "balanza", "balcón", "balde", "bambú", "banco", "banda", "baño", "barba", "barco", "barniz", "barro", "báscula", "bastón", "basura", "batalla", "batería", "batir", "batuta", "baúl", "bazar", "bebé", "bebida", "bello", "besar", "beso", "bestia", "bicho", "bien", "bingo", "blanco", "bloque", "blusa", "boa", "bobina", "bobo", "boca", "bocina", "boda", "bodega", "boina", "bola", "bolero", "bolsa", "bomba", "bondad", "bonito", "bono", "bonsái", "borde", "borrar", "bosque", "bote", "botín", "bóveda", "bozal", "bravo", "brazo", "brecha", "breve", "brillo", "brinco", "brisa", "broca", "broma", "bronce", "brote", "bruja", "brusco", "bruto", "buceo", "bucle", "bueno", "buey", "bufanda", "bufón", "búho", "buitre", "bulto", "burbuja", "burla", "burro", "buscar", "butaca", "buzón", "caballo", "cabeza", "cabina", "cabra", "cacao", "cadáver", "cadena", "caer", "café", "caída", "caimán", "caja", "cajón", "cal", "calamar", "calcio", "caldo", "calidad", "calle", "calma", "calor", "calvo", "cama", "cambio", "camello", "camino", "campo", "cáncer", "candil", "canela", "canguro", "canica", "canto", "caña", "cañón", "caoba", "caos", "capaz", "capitán", "capote", "captar", "capucha", "cara", "carbón", "cárcel", "careta", "carga", "cariño", "carne", "carpeta", "carro", "carta", "casa", "casco", "casero", "caspa", "castor", "catorce", "catre", "caudal", "causa", "cazo", "cebolla", "ceder", "cedro", "celda", "célebre", "celoso", "célula", "cemento", "ceniza", "centro", "cerca", "cerdo", "cereza", "cero", "cerrar", "certeza", "césped", "cetro", "chacal", "chaleco", "champú", "chancla", "chapa", "charla", "chico", "chiste", "chivo", "choque", "choza", "chuleta", "chupar", "ciclón", "ciego", "cielo", "cien", "cierto", "cifra", "cigarro", "cima", "cinco", "cine", "cinta", "ciprés", "circo", "ciruela", "cisne", "cita", "ciudad", "clamor", "clan", "claro", "clase", "clave", "cliente", "clima", "clínica", "cobre", "cocción", "cochino", "cocina", "coco", "código", "codo", "cofre", "coger", "cohete", "cojín", "cojo", "cola", "colcha", "colegio", "colgar", "colina", "collar", "colmo", "columna", "combate", "comer", "comida", "cómodo", "compra", "conde", "conejo", "conga", "conocer", "consejo", "contar", "copa", "copia", "corazón", "corbata", "corcho", "cordón", "corona", "correr", "coser", "cosmos", "costa", "cráneo", "cráter", "crear", "crecer", "creído", "crema", "cría", "crimen", "cripta", "crisis", "cromo", "crónica", "croqueta", "crudo", "cruz", "cuadro", "cuarto", "cuatro", "cubo", "cubrir", "cuchara", "cuello", "cuento", "cuerda", "cuesta", "cueva", "cuidar", "culebra", "culpa", "culto", "cumbre", "cumplir", "cuna", "cuneta", "cuota", "cupón", "cúpula", "curar", "curioso", "curso", "curva", "cutis", "dama", "danza", "dar", "dardo", "dátil", "deber", "débil", "década", "decir", "dedo", "defensa", "definir", "dejar", "delfín", "delgado", "delito", "demora", "denso", "dental", "deporte", "derecho", "derrota", "desayuno", "deseo", "desfile", "desnudo", "destino", "desvío", "detalle", "detener", "deuda", "día", "diablo", "diadema", "diamante", "diana", "diario", "dibujo", "dictar", "diente", "dieta", "diez", "difícil", "digno", "dilema", "diluir", "dinero", "directo", "dirigir", "disco", "diseño", "disfraz", "diva", "divino", "doble", "doce", "dolor", "domingo", "don", "donar", "dorado", "dormir", "dorso", "dos", "dosis", "dragón", "droga", "ducha", "duda", "duelo", "dueño", "dulce", "dúo", "duque", "durar", "dureza", "duro", "ébano", "ebrio", "echar", "eco", "ecuador", "edad", "edición", "edificio", "editor", "educar", "efecto", "eficaz", "eje", "ejemplo", "elefante", "elegir", "elemento", "elevar", "elipse", "élite", "elixir", "elogio", "eludir", "embudo", "emitir", "emoción", "empate", "empeño", "empleo", "empresa", "enano", "encargo", "enchufe", "encía", "enemigo", "enero", "enfado", "enfermo", "engaño", "enigma", "enlace", "enorme", "enredo", "ensayo", "enseñar", "entero", "entrar", "envase", "envío", "época", "equipo", "erizo", "escala", "escena", "escolar", "escribir", "escudo", "esencia", "esfera", "esfuerzo", "espada", "espejo", "espía", "esposa", "espuma", "esquí", "estar", "este", "estilo", "estufa", "etapa", "eterno", "ética", "etnia", "evadir", "evaluar", "evento", "evitar", "exacto", "examen", "exceso", "excusa", "exento", "exigir", "exilio", "existir", "éxito", "experto", "explicar", "exponer", "extremo", "fábrica", "fábula", "fachada", "fácil", "factor", "faena", "faja", "falda", "fallo", "falso", "faltar", "fama", "familia", "famoso", "faraón", "farmacia", "farol", "farsa", "fase", "fatiga", "fauna", "favor", "fax", "febrero", "fecha", "feliz", "feo", "feria", "feroz", "fértil", "fervor", "festín", "fiable", "fianza", "fiar", "fibra", "ficción", "ficha", "fideo", "fiebre", "fiel", "fiera", "fiesta", "figura", "fijar", "fijo", "fila", "filete", "filial", "filtro", "fin", "finca", "fingir", "finito", "firma", "flaco", "flauta", "flecha", "flor", "flota", "fluir", "flujo", "flúor", "fobia", "foca", "fogata", "fogón", "folio", "folleto", "fondo", "forma", "forro", "fortuna", "forzar", "fosa", "foto", "fracaso", "frágil", "franja", "frase", "fraude", "freír", "freno", "fresa", "frío", "frito", "fruta", "fuego", "fuente", "fuerza", "fuga", "fumar", "función", "funda", "furgón", "furia", "fusil", "fútbol", "futuro", "gacela", "gafas", "gaita", "gajo", "gala", "galería", "gallo", "gamba", "ganar", "gancho", "ganga", "ganso", "garaje", "garza", "gasolina", "gastar", "gato", "gavilán", "gemelo", "gemir", "gen", "género", "genio", "gente", "geranio", "gerente", "germen", "gesto", "gigante", "gimnasio", "girar", "giro", "glaciar", "globo", "gloria", "gol", "golfo", "goloso", "golpe", "goma", "gordo", "gorila", "gorra", "gota", "goteo", "gozar", "grada", "gráfico", "grano", "grasa", "gratis", "grave", "grieta", "grillo", "gripe", "gris", "grito", "grosor", "grúa", "grueso", "grumo", "grupo", "guante", "guapo", "guardia", "guerra", "guía", "guiño", "guion", "guiso", "guitarra", "gusano", "gustar", "haber", "hábil", "hablar", "hacer", "hacha", "hada", "hallar", "hamaca", "harina", "haz", "hazaña", "hebilla", "hebra", "hecho", "helado", "helio", "hembra", "herir", "hermano", "héroe", "hervir", "hielo", "hierro", "hígado", "higiene", "hijo", "himno", "historia", "hocico", "hogar", "hoguera", "hoja", "hombre", "hongo", "honor", "honra", "hora", "hormiga", "horno", "hostil", "hoyo", "hueco", "huelga", "huerta", "hueso", "huevo", "huida", "huir", "humano", "húmedo", "humilde", "humo", "hundir", "huracán", "hurto", "icono", "ideal", "idioma", "ídolo", "iglesia", "iglú", "igual", "ilegal", "ilusión", "imagen", "imán", "imitar", "impar", "imperio", "imponer", "impulso", "incapaz", "índice", "inerte", "infiel", "informe", "ingenio", "inicio", "inmenso", "inmune", "innato", "insecto", "instante", "interés", "íntimo", "intuir", "inútil", "invierno", "ira", "iris", "ironía", "isla", "islote", "jabalí", "jabón", "jamón", "jarabe", "jardín", "jarra", "jaula", "jazmín", "jefe", "jeringa", "jinete", "jornada", "joroba", "joven", "joya", "juerga", "jueves", "juez", "jugador", "jugo", "juguete", "juicio", "junco", "jungla", "junio", "juntar", "júpiter", "jurar", "justo", "juvenil", "juzgar", "kilo", "koala", "labio", "lacio", "lacra", "lado", "ladrón", "lagarto", "lágrima", "laguna", "laico", "lamer", "lámina", "lámpara", "lana", "lancha", "langosta", "lanza", "lápiz", "largo", "larva", "lástima", "lata", "látex", "latir", "laurel", "lavar", "lazo", "leal", "lección", "leche", "lector", "leer", "legión", "legumbre", "lejano", "lengua", "lento", "leña", "león", "leopardo", "lesión", "letal", "letra", "leve", "leyenda", "libertad", "libro", "licor", "líder", "lidiar", "lienzo", "liga", "ligero", "lima", "límite", "limón", "limpio", "lince", "lindo", "línea", "lingote", "lino", "linterna", "líquido", "liso", "lista", "litera", "litio", "litro", "llaga", "llama", "llanto", "llave", "llegar", "llenar", "llevar", "llorar", "llover", "lluvia", "lobo", "loción", "loco", "locura", "lógica", "logro", "lombriz", "lomo", "lonja", "lote", "lucha", "lucir", "lugar", "lujo", "luna", "lunes", "lupa", "lustro", "luto", "luz", "maceta", "macho", "madera", "madre", "maduro", "maestro", "mafia", "magia", "mago", "maíz", "maldad", "maleta", "malla", "malo", "mamá", "mambo", "mamut", "manco", "mando", "manejar", "manga", "maniquí", "manjar", "mano", "manso", "manta", "mañana", "mapa", "máquina", "mar", "marco", "marea", "marfil", "margen", "marido", "mármol", "marrón", "martes", "marzo", "masa", "máscara", "masivo", "matar", "materia", "matiz", "matriz", "máximo", "mayor", "mazorca", "mecha", "medalla", "medio", "médula", "mejilla", "mejor", "melena", "melón", "memoria", "menor", "mensaje", "mente", "menú", "mercado", "merengue", "mérito", "mes", "mesón", "meta", "meter", "método", "metro", "mezcla", "miedo", "miel", "miembro", "miga", "mil", "milagro", "militar", "millón", "mimo", "mina", "minero", "mínimo", "minuto", "miope", "mirar", "misa", "miseria", "misil", "mismo", "mitad", "mito", "mochila", "moción", "moda", "modelo", "moho", "mojar", "molde", "moler", "molino", "momento", "momia", "monarca", "moneda", "monja", "monto", "moño", "morada", "morder", "moreno", "morir", "morro", "morsa", "mortal", "mosca", "mostrar", "motivo", "mover", "móvil", "mozo", "mucho", "mudar", "mueble", "muela", "muerte", "muestra", "mugre", "mujer", "mula", "muleta", "multa", "mundo", "muñeca", "mural", "muro", "músculo", "museo", "musgo", "música", "muslo", "nácar", "nación", "nadar", "naipe", "naranja", "nariz", "narrar", "nasal", "natal", "nativo", "natural", "náusea", "naval", "nave", "navidad", "necio", "néctar", "negar", "negocio", "negro", "neón", "nervio", "neto", "neutro", "nevar", "nevera", "nicho", "nido", "niebla", "nieto", "niñez", "niño", "nítido", "nivel", "nobleza", "noche", "nómina", "noria", "norma", "norte", "nota", "noticia", "novato", "novela", "novio", "nube", "nuca", "núcleo", "nudillo", "nudo", "nuera", "nueve", "nuez", "nulo", "número", "nutria", "oasis", "obeso", "obispo", "objeto", "obra", "obrero", "observar", "obtener", "obvio", "oca", "ocaso", "océano", "ochenta", "ocho", "ocio", "ocre", "octavo", "octubre", "oculto", "ocupar", "ocurrir", "odiar", "odio", "odisea", "oeste", "ofensa", "oferta", "oficio", "ofrecer", "ogro", "oído", "oír", "ojo", "ola", "oleada", "olfato", "olivo", "olla", "olmo", "olor", "olvido", "ombligo", "onda", "onza", "opaco", "opción", "ópera", "opinar", "oponer", "optar", "óptica", "opuesto", "oración", "orador", "oral", "órbita", "orca", "orden", "oreja", "órgano", "orgía", "orgullo", "oriente", "origen", "orilla", "oro", "orquesta", "oruga", "osadía", "oscuro", "osezno", "oso", "ostra", "otoño", "otro", "oveja", "óvulo", "óxido", "oxígeno", "oyente", "ozono", "pacto", "padre", "paella", "página", "pago", "país", "pájaro", "palabra", "palco", "paleta", "pálido", "palma", "paloma", "palpar", "pan", "panal", "pánico", "pantera", "pañuelo", "papá", "papel", "papilla", "paquete", "parar", "parcela", "pared", "parir", "paro", "párpado", "parque", "párrafo", "parte", "pasar", "paseo", "pasión", "paso", "pasta", "pata", "patio", "patria", "pausa", "pauta", "pavo", "payaso", "peatón", "pecado", "pecera", "pecho", "pedal", "pedir", "pegar", "peine", "pelar", "peldaño", "pelea", "peligro", "pellejo", "pelo", "peluca", "pena", "pensar", "peñón", "peón", "peor", "pepino", "pequeño", "pera", "percha", "perder", "pereza", "perfil", "perico", "perla", "permiso", "perro", "persona", "pesa", "pesca", "pésimo", "pestaña", "pétalo", "petróleo", "pez", "pezuña", "picar", "pichón", "pie", "piedra", "pierna", "pieza", "pijama", "pilar", "piloto", "pimienta", "pino", "pintor", "pinza", "piña", "piojo", "pipa", "pirata", "pisar", "piscina", "piso", "pista", "pitón", "pizca", "placa", "plan", "plata", "playa", "plaza", "pleito", "pleno", "plomo", "pluma", "plural", "pobre", "poco", "poder", "podio", "poema", "poesía", "poeta", "polen", "policía", "pollo", "polvo", "pomada", "pomelo", "pomo", "pompa", "poner", "porción", "portal", "posada", "poseer", "posible", "poste", "potencia", "potro", "pozo", "prado", "precoz", "pregunta", "premio", "prensa", "preso", "previo", "primo", "príncipe", "prisión", "privar", "proa", "probar", "proceso", "producto", "proeza", "profesor", "programa", "prole", "promesa", "pronto", "propio", "próximo", "prueba", "público", "puchero", "pudor", "pueblo", "puerta", "puesto", "pulga", "pulir", "pulmón", "pulpo", "pulso", "puma", "punto", "puñal", "puño", "pupa", "pupila", "puré", "quedar", "queja", "quemar", "querer", "queso", "quieto", "química", "quince", "quitar", "rábano", "rabia", "rabo", "ración", "radical", "raíz", "rama", "rampa", "rancho", "rango", "rapaz", "rápido", "rapto", "rasgo", "raspa", "rato", "rayo", "raza", "razón", "reacción", "realidad", "rebaño", "rebote", "recaer", "receta", "rechazo", "recoger", "recreo", "recto", "recurso", "red", "redondo", "reducir", "reflejo", "reforma", "refrán", "refugio", "regalo", "regir", "regla", "regreso", "rehén", "reino", "reír", "reja", "relato", "relevo", "relieve", "relleno", "reloj", "remar", "remedio", "remo", "rencor", "rendir", "renta", "reparto", "repetir", "reposo", "reptil", "res", "rescate", "resina", "respeto", "resto", "resumen", "retiro", "retorno", "retrato", "reunir", "revés", "revista", "rey", "rezar", "rico", "riego", "rienda", "riesgo", "rifa", "rígido", "rigor", "rincón", "riñón", "río", "riqueza", "risa", "ritmo", "rito", "rizo", "roble", "roce", "rociar", "rodar", "rodeo", "rodilla", "roer", "rojizo", "rojo", "romero", "romper", "ron", "ronco", "ronda", "ropa", "ropero", "rosa", "rosca", "rostro", "rotar", "rubí", "rubor", "rudo", "rueda", "rugir", "ruido", "ruina", "ruleta", "rulo", "rumbo", "rumor", "ruptura", "ruta", "rutina", "sábado", "saber", "sabio", "sable", "sacar", "sagaz", "sagrado", "sala", "saldo", "salero", "salir", "salmón", "salón", "salsa", "salto", "salud", "salvar", "samba", "sanción", "sandía", "sanear", "sangre", "sanidad", "sano", "santo", "sapo", "saque", "sardina", "sartén", "sastre", "satán", "sauna", "saxofón", "sección", "seco", "secreto", "secta", "sed", "seguir", "seis", "sello", "selva", "semana", "semilla", "senda", "sensor", "señal", "señor", "separar", "sepia", "sequía", "ser", "serie", "sermón", "servir", "sesenta", "sesión", "seta", "setenta", "severo", "sexo", "sexto", "sidra", "siesta", "siete", "siglo", "signo", "sílaba", "silbar", "silencio", "silla", "símbolo", "simio", "sirena", "sistema", "sitio", "situar", "sobre", "socio", "sodio", "sol", "solapa", "soldado", "soledad", "sólido", "soltar", "solución", "sombra", "sondeo", "sonido", "sonoro", "sonrisa", "sopa", "soplar", "soporte", "sordo", "sorpresa", "sorteo", "sostén", "sótano", "suave", "subir", "suceso", "sudor", "suegra", "suelo", "sueño", "suerte", "sufrir", "sujeto", "sultán", "sumar", "superar", "suplir", "suponer", "supremo", "sur", "surco", "sureño", "surgir", "susto", "sutil", "tabaco", "tabique", "tabla", "tabú", "taco", "tacto", "tajo", "talar", "talco", "talento", "talla", "talón", "tamaño", "tambor", "tango", "tanque", "tapa", "tapete", "tapia", "tapón", "taquilla", "tarde", "tarea", "tarifa", "tarjeta", "tarot", "tarro", "tarta", "tatuaje", "tauro", "taza", "tazón", "teatro", "techo", "tecla", "técnica", "tejado", "tejer", "tejido", "tela", "teléfono", "tema", "temor", "templo", "tenaz", "tender", "tener", "tenis", "tenso", "teoría", "terapia", "terco", "término", "ternura", "terror", "tesis", "tesoro", "testigo", "tetera", "texto", "tez", "tibio", "tiburón", "tiempo", "tienda", "tierra", "tieso", "tigre", "tijera", "tilde", "timbre", "tímido", "timo", "tinta", "tío", "típico", "tipo", "tira", "tirón", "titán", "títere", "título", "tiza", "toalla", "tobillo", "tocar", "tocino", "todo", "toga", "toldo", "tomar", "tono", "tonto", "topar", "tope", "toque", "tórax", "torero", "tormenta", "torneo", "toro", "torpedo", "torre", "torso", "tortuga", "tos", "tosco", "toser", "tóxico", "trabajo", "tractor", "traer", "tráfico", "trago", "traje", "tramo", "trance", "trato", "trauma", "trazar", "trébol", "tregua", "treinta", "tren", "trepar", "tres", "tribu", "trigo", "tripa", "triste", "triunfo", "trofeo", "trompa", "tronco", "tropa", "trote", "trozo", "truco", "trueno", "trufa", "tubería", "tubo", "tuerto", "tumba", "tumor", "túnel", "túnica", "turbina", "turismo", "turno", "tutor", "ubicar", "úlcera", "umbral", "unidad", "unir", "universo", "uno", "untar", "uña", "urbano", "urbe", "urgente", "urna", "usar", "usuario", "útil", "utopía", "uva", "vaca", "vacío", "vacuna", "vagar", "vago", "vaina", "vajilla", "vale", "válido", "valle", "valor", "válvula", "vampiro", "vara", "variar", "varón", "vaso", "vecino", "vector", "vehículo", "veinte", "vejez", "vela", "velero", "veloz", "vena", "vencer", "venda", "veneno", "vengar", "venir", "venta", "venus", "ver", "verano", "verbo", "verde", "vereda", "verja", "verso", "verter", "vía", "viaje", "vibrar", "vicio", "víctima", "vida", "vídeo", "vidrio", "viejo", "viernes", "vigor", "vil", "villa", "vinagre", "vino", "viñedo", "violín", "viral", "virgo", "virtud", "visor", "víspera", "vista", "vitamina", "viudo", "vivaz", "vivero", "vivir", "vivo", "volcán", "volumen", "volver", "voraz", "votar", "voto", "voz", "vuelo", "vulgar", "yacer", "yate", "yegua", "yema", "yerno", "yeso", "yodo", "yoga", "yogur", "zafiro", "zanja", "zapato", "zarza", "zona", "zorro", "zumo", "zurdo"] static var simplifiedChineseWords: [String] = ["的", "一", "是", "在", "不", "了", "有", "和", "人", "这", "中", "大", "为", "上", "个", "国", "我", "以", "要", "他", "时", "来", "用", "们", "生", "到", "作", "地", "于", "出", "就", "分", "对", "成", "会", "可", "主", "发", "年", "动", "同", "工", "也", "能", "下", "过", "子", "说", "产", "种", "面", "而", "方", "后", "多", "定", "行", "学", "法", "所", "民", "得", "经", "十", "三", "之", "进", "着", "等", "部", "度", "家", "电", "力", "里", "如", "水", "化", "高", "自", "二", "理", "起", "小", "物", "现", "实", "加", "量", "都", "两", "体", "制", "机", "当", "使", "点", "从", "业", "本", "去", "把", "性", "好", "应", "开", "它", "合", "还", "因", "由", "其", "些", "然", "前", "外", "天", "政", "四", "日", "那", "社", "义", "事", "平", "形", "相", "全", "表", "间", "样", "与", "关", "各", "重", "新", "线", "内", "数", "正", "心", "反", "你", "明", "看", "原", "又", "么", "利", "比", "或", "但", "质", "气", "第", "向", "道", "命", "此", "变", "条", "只", "没", "结", "解", "问", "意", "建", "月", "公", "无", "系", "军", "很", "情", "者", "最", "立", "代", "想", "已", "通", "并", "提", "直", "题", "党", "程", "展", "五", "果", "料", "象", "员", "革", "位", "入", "常", "文", "总", "次", "品", "式", "活", "设", "及", "管", "特", "件", "长", "求", "老", "头", "基", "资", "边", "流", "路", "级", "少", "图", "山", "统", "接", "知", "较", "将", "组", "见", "计", "别", "她", "手", "角", "期", "根", "论", "运", "农", "指", "几", "九", "区", "强", "放", "决", "西", "被", "干", "做", "必", "战", "先", "回", "则", "任", "取", "据", "处", "队", "南", "给", "色", "光", "门", "即", "保", "治", "北", "造", "百", "规", "热", "领", "七", "海", "口", "东", "导", "器", "压", "志", "世", "金", "增", "争", "济", "阶", "油", "思", "术", "极", "交", "受", "联", "什", "认", "六", "共", "权", "收", "证", "改", "清", "美", "再", "采", "转", "更", "单", "风", "切", "打", "白", "教", "速", "花", "带", "安", "场", "身", "车", "例", "真", "务", "具", "万", "每", "目", "至", "达", "走", "积", "示", "议", "声", "报", "斗", "完", "类", "八", "离", "华", "名", "确", "才", "科", "张", "信", "马", "节", "话", "米", "整", "空", "元", "况", "今", "集", "温", "传", "土", "许", "步", "群", "广", "石", "记", "需", "段", "研", "界", "拉", "林", "律", "叫", "且", "究", "观", "越", "织", "装", "影", "算", "低", "持", "音", "众", "书", "布", "复", "容", "儿", "须", "际", "商", "非", "验", "连", "断", "深", "难", "近", "矿", "千", "周", "委", "素", "技", "备", "半", "办", "青", "省", "列", "习", "响", "约", "支", "般", "史", "感", "劳", "便", "团", "往", "酸", "历", "市", "克", "何", "除", "消", "构", "府", "称", "太", "准", "精", "值", "号", "率", "族", "维", "划", "选", "标", "写", "存", "候", "毛", "亲", "快", "效", "斯", "院", "查", "江", "型", "眼", "王", "按", "格", "养", "易", "置", "派", "层", "片", "始", "却", "专", "状", "育", "厂", "京", "识", "适", "属", "圆", "包", "火", "住", "调", "满", "县", "局", "照", "参", "红", "细", "引", "听", "该", "铁", "价", "严", "首", "底", "液", "官", "德", "随", "病", "苏", "失", "尔", "死", "讲", "配", "女", "黄", "推", "显", "谈", "罪", "神", "艺", "呢", "席", "含", "企", "望", "密", "批", "营", "项", "防", "举", "球", "英", "氧", "势", "告", "李", "台", "落", "木", "帮", "轮", "破", "亚", "师", "围", "注", "远", "字", "材", "排", "供", "河", "态", "封", "另", "施", "减", "树", "溶", "怎", "止", "案", "言", "士", "均", "武", "固", "叶", "鱼", "波", "视", "仅", "费", "紧", "爱", "左", "章", "早", "朝", "害", "续", "轻", "服", "试", "食", "充", "兵", "源", "判", "护", "司", "足", "某", "练", "差", "致", "板", "田", "降", "黑", "犯", "负", "击", "范", "继", "兴", "似", "余", "坚", "曲", "输", "修", "故", "城", "夫", "够", "送", "笔", "船", "占", "右", "财", "吃", "富", "春", "职", "觉", "汉", "画", "功", "巴", "跟", "虽", "杂", "飞", "检", "吸", "助", "升", "阳", "互", "初", "创", "抗", "考", "投", "坏", "策", "古", "径", "换", "未", "跑", "留", "钢", "曾", "端", "责", "站", "简", "述", "钱", "副", "尽", "帝", "射", "草", "冲", "承", "独", "令", "限", "阿", "宣", "环", "双", "请", "超", "微", "让", "控", "州", "良", "轴", "找", "否", "纪", "益", "依", "优", "顶", "础", "载", "倒", "房", "突", "坐", "粉", "敌", "略", "客", "袁", "冷", "胜", "绝", "析", "块", "剂", "测", "丝", "协", "诉", "念", "陈", "仍", "罗", "盐", "友", "洋", "错", "苦", "夜", "刑", "移", "频", "逐", "靠", "混", "母", "短", "皮", "终", "聚", "汽", "村", "云", "哪", "既", "距", "卫", "停", "烈", "央", "察", "烧", "迅", "境", "若", "印", "洲", "刻", "括", "激", "孔", "搞", "甚", "室", "待", "核", "校", "散", "侵", "吧", "甲", "游", "久", "菜", "味", "旧", "模", "湖", "货", "损", "预", "阻", "毫", "普", "稳", "乙", "妈", "植", "息", "扩", "银", "语", "挥", "酒", "守", "拿", "序", "纸", "医", "缺", "雨", "吗", "针", "刘", "啊", "急", "唱", "误", "训", "愿", "审", "附", "获", "茶", "鲜", "粮", "斤", "孩", "脱", "硫", "肥", "善", "龙", "演", "父", "渐", "血", "欢", "械", "掌", "歌", "沙", "刚", "攻", "谓", "盾", "讨", "晚", "粒", "乱", "燃", "矛", "乎", "杀", "药", "宁", "鲁", "贵", "钟", "煤", "读", "班", "伯", "香", "介", "迫", "句", "丰", "培", "握", "兰", "担", "弦", "蛋", "沉", "假", "穿", "执", "答", "乐", "谁", "顺", "烟", "缩", "征", "脸", "喜", "松", "脚", "困", "异", "免", "背", "星", "福", "买", "染", "井", "概", "慢", "怕", "磁", "倍", "祖", "皇", "促", "静", "补", "评", "翻", "肉", "践", "尼", "衣", "宽", "扬", "棉", "希", "伤", "操", "垂", "秋", "宜", "氢", "套", "督", "振", "架", "亮", "末", "宪", "庆", "编", "牛", "触", "映", "雷", "销", "诗", "座", "居", "抓", "裂", "胞", "呼", "娘", "景", "威", "绿", "晶", "厚", "盟", "衡", "鸡", "孙", "延", "危", "胶", "屋", "乡", "临", "陆", "顾", "掉", "呀", "灯", "岁", "措", "束", "耐", "剧", "玉", "赵", "跳", "哥", "季", "课", "凯", "胡", "额", "款", "绍", "卷", "齐", "伟", "蒸", "殖", "永", "宗", "苗", "川", "炉", "岩", "弱", "零", "杨", "奏", "沿", "露", "杆", "探", "滑", "镇", "饭", "浓", "航", "怀", "赶", "库", "夺", "伊", "灵", "税", "途", "灭", "赛", "归", "召", "鼓", "播", "盘", "裁", "险", "康", "唯", "录", "菌", "纯", "借", "糖", "盖", "横", "符", "私", "努", "堂", "域", "枪", "润", "幅", "哈", "竟", "熟", "虫", "泽", "脑", "壤", "碳", "欧", "遍", "侧", "寨", "敢", "彻", "虑", "斜", "薄", "庭", "纳", "弹", "饲", "伸", "折", "麦", "湿", "暗", "荷", "瓦", "塞", "床", "筑", "恶", "户", "访", "塔", "奇", "透", "梁", "刀", "旋", "迹", "卡", "氯", "遇", "份", "毒", "泥", "退", "洗", "摆", "灰", "彩", "卖", "耗", "夏", "择", "忙", "铜", "献", "硬", "予", "繁", "圈", "雪", "函", "亦", "抽", "篇", "阵", "阴", "丁", "尺", "追", "堆", "雄", "迎", "泛", "爸", "楼", "避", "谋", "吨", "野", "猪", "旗", "累", "偏", "典", "馆", "索", "秦", "脂", "潮", "爷", "豆", "忽", "托", "惊", "塑", "遗", "愈", "朱", "替", "纤", "粗", "倾", "尚", "痛", "楚", "谢", "奋", "购", "磨", "君", "池", "旁", "碎", "骨", "监", "捕", "弟", "暴", "割", "贯", "殊", "释", "词", "亡", "壁", "顿", "宝", "午", "尘", "闻", "揭", "炮", "残", "冬", "桥", "妇", "警", "综", "招", "吴", "付", "浮", "遭", "徐", "您", "摇", "谷", "赞", "箱", "隔", "订", "男", "吹", "园", "纷", "唐", "败", "宋", "玻", "巨", "耕", "坦", "荣", "闭", "湾", "键", "凡", "驻", "锅", "救", "恩", "剥", "凝", "碱", "齿", "截", "炼", "麻", "纺", "禁", "废", "盛", "版", "缓", "净", "睛", "昌", "婚", "涉", "筒", "嘴", "插", "岸", "朗", "庄", "街", "藏", "姑", "贸", "腐", "奴", "啦", "惯", "乘", "伙", "恢", "匀", "纱", "扎", "辩", "耳", "彪", "臣", "亿", "璃", "抵", "脉", "秀", "萨", "俄", "网", "舞", "店", "喷", "纵", "寸", "汗", "挂", "洪", "贺", "闪", "柬", "爆", "烯", "津", "稻", "墙", "软", "勇", "像", "滚", "厘", "蒙", "芳", "肯", "坡", "柱", "荡", "腿", "仪", "旅", "尾", "轧", "冰", "贡", "登", "黎", "削", "钻", "勒", "逃", "障", "氨", "郭", "峰", "币", "港", "伏", "轨", "亩", "毕", "擦", "莫", "刺", "浪", "秘", "援", "株", "健", "售", "股", "岛", "甘", "泡", "睡", "童", "铸", "汤", "阀", "休", "汇", "舍", "牧", "绕", "炸", "哲", "磷", "绩", "朋", "淡", "尖", "启", "陷", "柴", "呈", "徒", "颜", "泪", "稍", "忘", "泵", "蓝", "拖", "洞", "授", "镜", "辛", "壮", "锋", "贫", "虚", "弯", "摩", "泰", "幼", "廷", "尊", "窗", "纲", "弄", "隶", "疑", "氏", "宫", "姐", "震", "瑞", "怪", "尤", "琴", "循", "描", "膜", "违", "夹", "腰", "缘", "珠", "穷", "森", "枝", "竹", "沟", "催", "绳", "忆", "邦", "剩", "幸", "浆", "栏", "拥", "牙", "贮", "礼", "滤", "钠", "纹", "罢", "拍", "咱", "喊", "袖", "埃", "勤", "罚", "焦", "潜", "伍", "墨", "欲", "缝", "姓", "刊", "饱", "仿", "奖", "铝", "鬼", "丽", "跨", "默", "挖", "链", "扫", "喝", "袋", "炭", "污", "幕", "诸", "弧", "励", "梅", "奶", "洁", "灾", "舟", "鉴", "苯", "讼", "抱", "毁", "懂", "寒", "智", "埔", "寄", "届", "跃", "渡", "挑", "丹", "艰", "贝", "碰", "拔", "爹", "戴", "码", "梦", "芽", "熔", "赤", "渔", "哭", "敬", "颗", "奔", "铅", "仲", "虎", "稀", "妹", "乏", "珍", "申", "桌", "遵", "允", "隆", "螺", "仓", "魏", "锐", "晓", "氮", "兼", "隐", "碍", "赫", "拨", "忠", "肃", "缸", "牵", "抢", "博", "巧", "壳", "兄", "杜", "讯", "诚", "碧", "祥", "柯", "页", "巡", "矩", "悲", "灌", "龄", "伦", "票", "寻", "桂", "铺", "圣", "恐", "恰", "郑", "趣", "抬", "荒", "腾", "贴", "柔", "滴", "猛", "阔", "辆", "妻", "填", "撤", "储", "签", "闹", "扰", "紫", "砂", "递", "戏", "吊", "陶", "伐", "喂", "疗", "瓶", "婆", "抚", "臂", "摸", "忍", "虾", "蜡", "邻", "胸", "巩", "挤", "偶", "弃", "槽", "劲", "乳", "邓", "吉", "仁", "烂", "砖", "租", "乌", "舰", "伴", "瓜", "浅", "丙", "暂", "燥", "橡", "柳", "迷", "暖", "牌", "秧", "胆", "详", "簧", "踏", "瓷", "谱", "呆", "宾", "糊", "洛", "辉", "愤", "竞", "隙", "怒", "粘", "乃", "绪", "肩", "籍", "敏", "涂", "熙", "皆", "侦", "悬", "掘", "享", "纠", "醒", "狂", "锁", "淀", "恨", "牲", "霸", "爬", "赏", "逆", "玩", "陵", "祝", "秒", "浙", "貌", "役", "彼", "悉", "鸭", "趋", "凤", "晨", "畜", "辈", "秩", "卵", "署", "梯", "炎", "滩", "棋", "驱", "筛", "峡", "冒", "啥", "寿", "译", "浸", "泉", "帽", "迟", "硅", "疆", "贷", "漏", "稿", "冠", "嫩", "胁", "芯", "牢", "叛", "蚀", "奥", "鸣", "岭", "羊", "凭", "串", "塘", "绘", "酵", "融", "盆", "锡", "庙", "筹", "冻", "辅", "摄", "袭", "筋", "拒", "僚", "旱", "钾", "鸟", "漆", "沈", "眉", "疏", "添", "棒", "穗", "硝", "韩", "逼", "扭", "侨", "凉", "挺", "碗", "栽", "炒", "杯", "患", "馏", "劝", "豪", "辽", "勃", "鸿", "旦", "吏", "拜", "狗", "埋", "辊", "掩", "饮", "搬", "骂", "辞", "勾", "扣", "估", "蒋", "绒", "雾", "丈", "朵", "姆", "拟", "宇", "辑", "陕", "雕", "偿", "蓄", "崇", "剪", "倡", "厅", "咬", "驶", "薯", "刷", "斥", "番", "赋", "奉", "佛", "浇", "漫", "曼", "扇", "钙", "桃", "扶", "仔", "返", "俗", "亏", "腔", "鞋", "棱", "覆", "框", "悄", "叔", "撞", "骗", "勘", "旺", "沸", "孤", "吐", "孟", "渠", "屈", "疾", "妙", "惜", "仰", "狠", "胀", "谐", "抛", "霉", "桑", "岗", "嘛", "衰", "盗", "渗", "脏", "赖", "涌", "甜", "曹", "阅", "肌", "哩", "厉", "烃", "纬", "毅", "昨", "伪", "症", "煮", "叹", "钉", "搭", "茎", "笼", "酷", "偷", "弓", "锥", "恒", "杰", "坑", "鼻", "翼", "纶", "叙", "狱", "逮", "罐", "络", "棚", "抑", "膨", "蔬", "寺", "骤", "穆", "冶", "枯", "册", "尸", "凸", "绅", "坯", "牺", "焰", "轰", "欣", "晋", "瘦", "御", "锭", "锦", "丧", "旬", "锻", "垄", "搜", "扑", "邀", "亭", "酯", "迈", "舒", "脆", "酶", "闲", "忧", "酚", "顽", "羽", "涨", "卸", "仗", "陪", "辟", "惩", "杭", "姚", "肚", "捉", "飘", "漂", "昆", "欺", "吾", "郎", "烷", "汁", "呵", "饰", "萧", "雅", "邮", "迁", "燕", "撒", "姻", "赴", "宴", "烦", "债", "帐", "斑", "铃", "旨", "醇", "董", "饼", "雏", "姿", "拌", "傅", "腹", "妥", "揉", "贤", "拆", "歪", "葡", "胺", "丢", "浩", "徽", "昂", "垫", "挡", "览", "贪", "慰", "缴", "汪", "慌", "冯", "诺", "姜", "谊", "凶", "劣", "诬", "耀", "昏", "躺", "盈", "骑", "乔", "溪", "丛", "卢", "抹", "闷", "咨", "刮", "驾", "缆", "悟", "摘", "铒", "掷", "颇", "幻", "柄", "惠", "惨", "佳", "仇", "腊", "窝", "涤", "剑", "瞧", "堡", "泼", "葱", "罩", "霍", "捞", "胎", "苍", "滨", "俩", "捅", "湘", "砍", "霞", "邵", "萄", "疯", "淮", "遂", "熊", "粪", "烘", "宿", "档", "戈", "驳", "嫂", "裕", "徙", "箭", "捐", "肠", "撑", "晒", "辨", "殿", "莲", "摊", "搅", "酱", "屏", "疫", "哀", "蔡", "堵", "沫", "皱", "畅", "叠", "阁", "莱", "敲", "辖", "钩", "痕", "坝", "巷", "饿", "祸", "丘", "玄", "溜", "曰", "逻", "彭", "尝", "卿", "妨", "艇", "吞", "韦", "怨", "矮", "歇"] static var traditionalChineseWords: [String] = ["的", "一", "是", "在", "不", "了", "有", "和", "人", "這", "中", "大", "為", "上", "個", "國", "我", "以", "要", "他", "時", "來", "用", "們", "生", "到", "作", "地", "於", "出", "就", "分", "對", "成", "會", "可", "主", "發", "年", "動", "同", "工", "也", "能", "下", "過", "子", "說", "產", "種", "面", "而", "方", "後", "多", "定", "行", "學", "法", "所", "民", "得", "經", "十", "三", "之", "進", "著", "等", "部", "度", "家", "電", "力", "裡", "如", "水", "化", "高", "自", "二", "理", "起", "小", "物", "現", "實", "加", "量", "都", "兩", "體", "制", "機", "當", "使", "點", "從", "業", "本", "去", "把", "性", "好", "應", "開", "它", "合", "還", "因", "由", "其", "些", "然", "前", "外", "天", "政", "四", "日", "那", "社", "義", "事", "平", "形", "相", "全", "表", "間", "樣", "與", "關", "各", "重", "新", "線", "內", "數", "正", "心", "反", "你", "明", "看", "原", "又", "麼", "利", "比", "或", "但", "質", "氣", "第", "向", "道", "命", "此", "變", "條", "只", "沒", "結", "解", "問", "意", "建", "月", "公", "無", "系", "軍", "很", "情", "者", "最", "立", "代", "想", "已", "通", "並", "提", "直", "題", "黨", "程", "展", "五", "果", "料", "象", "員", "革", "位", "入", "常", "文", "總", "次", "品", "式", "活", "設", "及", "管", "特", "件", "長", "求", "老", "頭", "基", "資", "邊", "流", "路", "級", "少", "圖", "山", "統", "接", "知", "較", "將", "組", "見", "計", "別", "她", "手", "角", "期", "根", "論", "運", "農", "指", "幾", "九", "區", "強", "放", "決", "西", "被", "幹", "做", "必", "戰", "先", "回", "則", "任", "取", "據", "處", "隊", "南", "給", "色", "光", "門", "即", "保", "治", "北", "造", "百", "規", "熱", "領", "七", "海", "口", "東", "導", "器", "壓", "志", "世", "金", "增", "爭", "濟", "階", "油", "思", "術", "極", "交", "受", "聯", "什", "認", "六", "共", "權", "收", "證", "改", "清", "美", "再", "採", "轉", "更", "單", "風", "切", "打", "白", "教", "速", "花", "帶", "安", "場", "身", "車", "例", "真", "務", "具", "萬", "每", "目", "至", "達", "走", "積", "示", "議", "聲", "報", "鬥", "完", "類", "八", "離", "華", "名", "確", "才", "科", "張", "信", "馬", "節", "話", "米", "整", "空", "元", "況", "今", "集", "溫", "傳", "土", "許", "步", "群", "廣", "石", "記", "需", "段", "研", "界", "拉", "林", "律", "叫", "且", "究", "觀", "越", "織", "裝", "影", "算", "低", "持", "音", "眾", "書", "布", "复", "容", "兒", "須", "際", "商", "非", "驗", "連", "斷", "深", "難", "近", "礦", "千", "週", "委", "素", "技", "備", "半", "辦", "青", "省", "列", "習", "響", "約", "支", "般", "史", "感", "勞", "便", "團", "往", "酸", "歷", "市", "克", "何", "除", "消", "構", "府", "稱", "太", "準", "精", "值", "號", "率", "族", "維", "劃", "選", "標", "寫", "存", "候", "毛", "親", "快", "效", "斯", "院", "查", "江", "型", "眼", "王", "按", "格", "養", "易", "置", "派", "層", "片", "始", "卻", "專", "狀", "育", "廠", "京", "識", "適", "屬", "圓", "包", "火", "住", "調", "滿", "縣", "局", "照", "參", "紅", "細", "引", "聽", "該", "鐵", "價", "嚴", "首", "底", "液", "官", "德", "隨", "病", "蘇", "失", "爾", "死", "講", "配", "女", "黃", "推", "顯", "談", "罪", "神", "藝", "呢", "席", "含", "企", "望", "密", "批", "營", "項", "防", "舉", "球", "英", "氧", "勢", "告", "李", "台", "落", "木", "幫", "輪", "破", "亞", "師", "圍", "注", "遠", "字", "材", "排", "供", "河", "態", "封", "另", "施", "減", "樹", "溶", "怎", "止", "案", "言", "士", "均", "武", "固", "葉", "魚", "波", "視", "僅", "費", "緊", "愛", "左", "章", "早", "朝", "害", "續", "輕", "服", "試", "食", "充", "兵", "源", "判", "護", "司", "足", "某", "練", "差", "致", "板", "田", "降", "黑", "犯", "負", "擊", "范", "繼", "興", "似", "餘", "堅", "曲", "輸", "修", "故", "城", "夫", "夠", "送", "筆", "船", "佔", "右", "財", "吃", "富", "春", "職", "覺", "漢", "畫", "功", "巴", "跟", "雖", "雜", "飛", "檢", "吸", "助", "昇", "陽", "互", "初", "創", "抗", "考", "投", "壞", "策", "古", "徑", "換", "未", "跑", "留", "鋼", "曾", "端", "責", "站", "簡", "述", "錢", "副", "盡", "帝", "射", "草", "衝", "承", "獨", "令", "限", "阿", "宣", "環", "雙", "請", "超", "微", "讓", "控", "州", "良", "軸", "找", "否", "紀", "益", "依", "優", "頂", "礎", "載", "倒", "房", "突", "坐", "粉", "敵", "略", "客", "袁", "冷", "勝", "絕", "析", "塊", "劑", "測", "絲", "協", "訴", "念", "陳", "仍", "羅", "鹽", "友", "洋", "錯", "苦", "夜", "刑", "移", "頻", "逐", "靠", "混", "母", "短", "皮", "終", "聚", "汽", "村", "雲", "哪", "既", "距", "衛", "停", "烈", "央", "察", "燒", "迅", "境", "若", "印", "洲", "刻", "括", "激", "孔", "搞", "甚", "室", "待", "核", "校", "散", "侵", "吧", "甲", "遊", "久", "菜", "味", "舊", "模", "湖", "貨", "損", "預", "阻", "毫", "普", "穩", "乙", "媽", "植", "息", "擴", "銀", "語", "揮", "酒", "守", "拿", "序", "紙", "醫", "缺", "雨", "嗎", "針", "劉", "啊", "急", "唱", "誤", "訓", "願", "審", "附", "獲", "茶", "鮮", "糧", "斤", "孩", "脫", "硫", "肥", "善", "龍", "演", "父", "漸", "血", "歡", "械", "掌", "歌", "沙", "剛", "攻", "謂", "盾", "討", "晚", "粒", "亂", "燃", "矛", "乎", "殺", "藥", "寧", "魯", "貴", "鐘", "煤", "讀", "班", "伯", "香", "介", "迫", "句", "豐", "培", "握", "蘭", "擔", "弦", "蛋", "沉", "假", "穿", "執", "答", "樂", "誰", "順", "煙", "縮", "徵", "臉", "喜", "松", "腳", "困", "異", "免", "背", "星", "福", "買", "染", "井", "概", "慢", "怕", "磁", "倍", "祖", "皇", "促", "靜", "補", "評", "翻", "肉", "踐", "尼", "衣", "寬", "揚", "棉", "希", "傷", "操", "垂", "秋", "宜", "氫", "套", "督", "振", "架", "亮", "末", "憲", "慶", "編", "牛", "觸", "映", "雷", "銷", "詩", "座", "居", "抓", "裂", "胞", "呼", "娘", "景", "威", "綠", "晶", "厚", "盟", "衡", "雞", "孫", "延", "危", "膠", "屋", "鄉", "臨", "陸", "顧", "掉", "呀", "燈", "歲", "措", "束", "耐", "劇", "玉", "趙", "跳", "哥", "季", "課", "凱", "胡", "額", "款", "紹", "卷", "齊", "偉", "蒸", "殖", "永", "宗", "苗", "川", "爐", "岩", "弱", "零", "楊", "奏", "沿", "露", "桿", "探", "滑", "鎮", "飯", "濃", "航", "懷", "趕", "庫", "奪", "伊", "靈", "稅", "途", "滅", "賽", "歸", "召", "鼓", "播", "盤", "裁", "險", "康", "唯", "錄", "菌", "純", "借", "糖", "蓋", "橫", "符", "私", "努", "堂", "域", "槍", "潤", "幅", "哈", "竟", "熟", "蟲", "澤", "腦", "壤", "碳", "歐", "遍", "側", "寨", "敢", "徹", "慮", "斜", "薄", "庭", "納", "彈", "飼", "伸", "折", "麥", "濕", "暗", "荷", "瓦", "塞", "床", "築", "惡", "戶", "訪", "塔", "奇", "透", "梁", "刀", "旋", "跡", "卡", "氯", "遇", "份", "毒", "泥", "退", "洗", "擺", "灰", "彩", "賣", "耗", "夏", "擇", "忙", "銅", "獻", "硬", "予", "繁", "圈", "雪", "函", "亦", "抽", "篇", "陣", "陰", "丁", "尺", "追", "堆", "雄", "迎", "泛", "爸", "樓", "避", "謀", "噸", "野", "豬", "旗", "累", "偏", "典", "館", "索", "秦", "脂", "潮", "爺", "豆", "忽", "托", "驚", "塑", "遺", "愈", "朱", "替", "纖", "粗", "傾", "尚", "痛", "楚", "謝", "奮", "購", "磨", "君", "池", "旁", "碎", "骨", "監", "捕", "弟", "暴", "割", "貫", "殊", "釋", "詞", "亡", "壁", "頓", "寶", "午", "塵", "聞", "揭", "炮", "殘", "冬", "橋", "婦", "警", "綜", "招", "吳", "付", "浮", "遭", "徐", "您", "搖", "谷", "贊", "箱", "隔", "訂", "男", "吹", "園", "紛", "唐", "敗", "宋", "玻", "巨", "耕", "坦", "榮", "閉", "灣", "鍵", "凡", "駐", "鍋", "救", "恩", "剝", "凝", "鹼", "齒", "截", "煉", "麻", "紡", "禁", "廢", "盛", "版", "緩", "淨", "睛", "昌", "婚", "涉", "筒", "嘴", "插", "岸", "朗", "莊", "街", "藏", "姑", "貿", "腐", "奴", "啦", "慣", "乘", "夥", "恢", "勻", "紗", "扎", "辯", "耳", "彪", "臣", "億", "璃", "抵", "脈", "秀", "薩", "俄", "網", "舞", "店", "噴", "縱", "寸", "汗", "掛", "洪", "賀", "閃", "柬", "爆", "烯", "津", "稻", "牆", "軟", "勇", "像", "滾", "厘", "蒙", "芳", "肯", "坡", "柱", "盪", "腿", "儀", "旅", "尾", "軋", "冰", "貢", "登", "黎", "削", "鑽", "勒", "逃", "障", "氨", "郭", "峰", "幣", "港", "伏", "軌", "畝", "畢", "擦", "莫", "刺", "浪", "秘", "援", "株", "健", "售", "股", "島", "甘", "泡", "睡", "童", "鑄", "湯", "閥", "休", "匯", "舍", "牧", "繞", "炸", "哲", "磷", "績", "朋", "淡", "尖", "啟", "陷", "柴", "呈", "徒", "顏", "淚", "稍", "忘", "泵", "藍", "拖", "洞", "授", "鏡", "辛", "壯", "鋒", "貧", "虛", "彎", "摩", "泰", "幼", "廷", "尊", "窗", "綱", "弄", "隸", "疑", "氏", "宮", "姐", "震", "瑞", "怪", "尤", "琴", "循", "描", "膜", "違", "夾", "腰", "緣", "珠", "窮", "森", "枝", "竹", "溝", "催", "繩", "憶", "邦", "剩", "幸", "漿", "欄", "擁", "牙", "貯", "禮", "濾", "鈉", "紋", "罷", "拍", "咱", "喊", "袖", "埃", "勤", "罰", "焦", "潛", "伍", "墨", "欲", "縫", "姓", "刊", "飽", "仿", "獎", "鋁", "鬼", "麗", "跨", "默", "挖", "鏈", "掃", "喝", "袋", "炭", "污", "幕", "諸", "弧", "勵", "梅", "奶", "潔", "災", "舟", "鑑", "苯", "訟", "抱", "毀", "懂", "寒", "智", "埔", "寄", "屆", "躍", "渡", "挑", "丹", "艱", "貝", "碰", "拔", "爹", "戴", "碼", "夢", "芽", "熔", "赤", "漁", "哭", "敬", "顆", "奔", "鉛", "仲", "虎", "稀", "妹", "乏", "珍", "申", "桌", "遵", "允", "隆", "螺", "倉", "魏", "銳", "曉", "氮", "兼", "隱", "礙", "赫", "撥", "忠", "肅", "缸", "牽", "搶", "博", "巧", "殼", "兄", "杜", "訊", "誠", "碧", "祥", "柯", "頁", "巡", "矩", "悲", "灌", "齡", "倫", "票", "尋", "桂", "鋪", "聖", "恐", "恰", "鄭", "趣", "抬", "荒", "騰", "貼", "柔", "滴", "猛", "闊", "輛", "妻", "填", "撤", "儲", "簽", "鬧", "擾", "紫", "砂", "遞", "戲", "吊", "陶", "伐", "餵", "療", "瓶", "婆", "撫", "臂", "摸", "忍", "蝦", "蠟", "鄰", "胸", "鞏", "擠", "偶", "棄", "槽", "勁", "乳", "鄧", "吉", "仁", "爛", "磚", "租", "烏", "艦", "伴", "瓜", "淺", "丙", "暫", "燥", "橡", "柳", "迷", "暖", "牌", "秧", "膽", "詳", "簧", "踏", "瓷", "譜", "呆", "賓", "糊", "洛", "輝", "憤", "競", "隙", "怒", "粘", "乃", "緒", "肩", "籍", "敏", "塗", "熙", "皆", "偵", "懸", "掘", "享", "糾", "醒", "狂", "鎖", "淀", "恨", "牲", "霸", "爬", "賞", "逆", "玩", "陵", "祝", "秒", "浙", "貌", "役", "彼", "悉", "鴨", "趨", "鳳", "晨", "畜", "輩", "秩", "卵", "署", "梯", "炎", "灘", "棋", "驅", "篩", "峽", "冒", "啥", "壽", "譯", "浸", "泉", "帽", "遲", "矽", "疆", "貸", "漏", "稿", "冠", "嫩", "脅", "芯", "牢", "叛", "蝕", "奧", "鳴", "嶺", "羊", "憑", "串", "塘", "繪", "酵", "融", "盆", "錫", "廟", "籌", "凍", "輔", "攝", "襲", "筋", "拒", "僚", "旱", "鉀", "鳥", "漆", "沈", "眉", "疏", "添", "棒", "穗", "硝", "韓", "逼", "扭", "僑", "涼", "挺", "碗", "栽", "炒", "杯", "患", "餾", "勸", "豪", "遼", "勃", "鴻", "旦", "吏", "拜", "狗", "埋", "輥", "掩", "飲", "搬", "罵", "辭", "勾", "扣", "估", "蔣", "絨", "霧", "丈", "朵", "姆", "擬", "宇", "輯", "陝", "雕", "償", "蓄", "崇", "剪", "倡", "廳", "咬", "駛", "薯", "刷", "斥", "番", "賦", "奉", "佛", "澆", "漫", "曼", "扇", "鈣", "桃", "扶", "仔", "返", "俗", "虧", "腔", "鞋", "棱", "覆", "框", "悄", "叔", "撞", "騙", "勘", "旺", "沸", "孤", "吐", "孟", "渠", "屈", "疾", "妙", "惜", "仰", "狠", "脹", "諧", "拋", "黴", "桑", "崗", "嘛", "衰", "盜", "滲", "臟", "賴", "湧", "甜", "曹", "閱", "肌", "哩", "厲", "烴", "緯", "毅", "昨", "偽", "症", "煮", "嘆", "釘", "搭", "莖", "籠", "酷", "偷", "弓", "錐", "恆", "傑", "坑", "鼻", "翼", "綸", "敘", "獄", "逮", "罐", "絡", "棚", "抑", "膨", "蔬", "寺", "驟", "穆", "冶", "枯", "冊", "屍", "凸", "紳", "坯", "犧", "焰", "轟", "欣", "晉", "瘦", "禦", "錠", "錦", "喪", "旬", "鍛", "壟", "搜", "撲", "邀", "亭", "酯", "邁", "舒", "脆", "酶", "閒", "憂", "酚", "頑", "羽", "漲", "卸", "仗", "陪", "闢", "懲", "杭", "姚", "肚", "捉", "飄", "漂", "昆", "欺", "吾", "郎", "烷", "汁", "呵", "飾", "蕭", "雅", "郵", "遷", "燕", "撒", "姻", "赴", "宴", "煩", "債", "帳", "斑", "鈴", "旨", "醇", "董", "餅", "雛", "姿", "拌", "傅", "腹", "妥", "揉", "賢", "拆", "歪", "葡", "胺", "丟", "浩", "徽", "昂", "墊", "擋", "覽", "貪", "慰", "繳", "汪", "慌", "馮", "諾", "姜", "誼", "兇", "劣", "誣", "耀", "昏", "躺", "盈", "騎", "喬", "溪", "叢", "盧", "抹", "悶", "諮", "刮", "駕", "纜", "悟", "摘", "鉺", "擲", "頗", "幻", "柄", "惠", "慘", "佳", "仇", "臘", "窩", "滌", "劍", "瞧", "堡", "潑", "蔥", "罩", "霍", "撈", "胎", "蒼", "濱", "倆", "捅", "湘", "砍", "霞", "邵", "萄", "瘋", "淮", "遂", "熊", "糞", "烘", "宿", "檔", "戈", "駁", "嫂", "裕", "徙", "箭", "捐", "腸", "撐", "曬", "辨", "殿", "蓮", "攤", "攪", "醬", "屏", "疫", "哀", "蔡", "堵", "沫", "皺", "暢", "疊", "閣", "萊", "敲", "轄", "鉤", "痕", "壩", "巷", "餓", "禍", "丘", "玄", "溜", "曰", "邏", "彭", "嘗", "卿", "妨", "艇", "吞", "韋", "怨", "矮", "歇"] static var frenchWords: [String] = ["abaisser", "abandon", "abdiquer", "abeille", "abolir", "aborder", "aboutir", "aboyer", "abrasif", "abreuver", "abriter", "abroger", "abrupt", "absence", "absolu", "absurde", "abusif", "abyssal", "académie", "acajou", "acarien", "accabler", "accepter", "acclamer", "accolade", "accroche", "accuser", "acerbe", "achat", "acheter", "aciduler", "acier", "acompte", "acquérir", "acronyme", "acteur", "actif", "actuel", "adepte", "adéquat", "adhésif", "adjectif", "adjuger", "admettre", "admirer", "adopter", "adorer", "adoucir", "adresse", "adroit", "adulte", "adverbe", "aérer", "aéronef", "affaire", "affecter", "affiche", "affreux", "affubler", "agacer", "agencer", "agile", "agiter", "agrafer", "agréable", "agrume", "aider", "aiguille", "ailier", "aimable", "aisance", "ajouter", "ajuster", "alarmer", "alchimie", "alerte", "algèbre", "algue", "aliéner", "aliment", "alléger", "alliage", "allouer", "allumer", "alourdir", "alpaga", "altesse", "alvéole", "amateur", "ambigu", "ambre", "aménager", "amertume", "amidon", "amiral", "amorcer", "amour", "amovible", "amphibie", "ampleur", "amusant", "analyse", "anaphore", "anarchie", "anatomie", "ancien", "anéantir", "angle", "angoisse", "anguleux", "animal", "annexer", "annonce", "annuel", "anodin", "anomalie", "anonyme", "anormal", "antenne", "antidote", "anxieux", "apaiser", "apéritif", "aplanir", "apologie", "appareil", "appeler", "apporter", "appuyer", "aquarium", "aqueduc", "arbitre", "arbuste", "ardeur", "ardoise", "argent", "arlequin", "armature", "armement", "armoire", "armure", "arpenter", "arracher", "arriver", "arroser", "arsenic", "artériel", "article", "aspect", "asphalte", "aspirer", "assaut", "asservir", "assiette", "associer", "assurer", "asticot", "astre", "astuce", "atelier", "atome", "atrium", "atroce", "attaque", "attentif", "attirer", "attraper", "aubaine", "auberge", "audace", "audible", "augurer", "aurore", "automne", "autruche", "avaler", "avancer", "avarice", "avenir", "averse", "aveugle", "aviateur", "avide", "avion", "aviser", "avoine", "avouer", "avril", "axial", "axiome", "badge", "bafouer", "bagage", "baguette", "baignade", "balancer", "balcon", "baleine", "balisage", "bambin", "bancaire", "bandage", "banlieue", "bannière", "banquier", "barbier", "baril", "baron", "barque", "barrage", "bassin", "bastion", "bataille", "bateau", "batterie", "baudrier", "bavarder", "belette", "bélier", "belote", "bénéfice", "berceau", "berger", "berline", "bermuda", "besace", "besogne", "bétail", "beurre", "biberon", "bicycle", "bidule", "bijou", "bilan", "bilingue", "billard", "binaire", "biologie", "biopsie", "biotype", "biscuit", "bison", "bistouri", "bitume", "bizarre", "blafard", "blague", "blanchir", "blessant", "blinder", "blond", "bloquer", "blouson", "bobard", "bobine", "boire", "boiser", "bolide", "bonbon", "bondir", "bonheur", "bonifier", "bonus", "bordure", "borne", "botte", "boucle", "boueux", "bougie", "boulon", "bouquin", "bourse", "boussole", "boutique", "boxeur", "branche", "brasier", "brave", "brebis", "brèche", "breuvage", "bricoler", "brigade", "brillant", "brioche", "brique", "brochure", "broder", "bronzer", "brousse", "broyeur", "brume", "brusque", "brutal", "bruyant", "buffle", "buisson", "bulletin", "bureau", "burin", "bustier", "butiner", "butoir", "buvable", "buvette", "cabanon", "cabine", "cachette", "cadeau", "cadre", "caféine", "caillou", "caisson", "calculer", "calepin", "calibre", "calmer", "calomnie", "calvaire", "camarade", "caméra", "camion", "campagne", "canal", "caneton", "canon", "cantine", "canular", "capable", "caporal", "caprice", "capsule", "capter", "capuche", "carabine", "carbone", "caresser", "caribou", "carnage", "carotte", "carreau", "carton", "cascade", "casier", "casque", "cassure", "causer", "caution", "cavalier", "caverne", "caviar", "cédille", "ceinture", "céleste", "cellule", "cendrier", "censurer", "central", "cercle", "cérébral", "cerise", "cerner", "cerveau", "cesser", "chagrin", "chaise", "chaleur", "chambre", "chance", "chapitre", "charbon", "chasseur", "chaton", "chausson", "chavirer", "chemise", "chenille", "chéquier", "chercher", "cheval", "chien", "chiffre", "chignon", "chimère", "chiot", "chlorure", "chocolat", "choisir", "chose", "chouette", "chrome", "chute", "cigare", "cigogne", "cimenter", "cinéma", "cintrer", "circuler", "cirer", "cirque", "citerne", "citoyen", "citron", "civil", "clairon", "clameur", "claquer", "classe", "clavier", "client", "cligner", "climat", "clivage", "cloche", "clonage", "cloporte", "cobalt", "cobra", "cocasse", "cocotier", "coder", "codifier", "coffre", "cogner", "cohésion", "coiffer", "coincer", "colère", "colibri", "colline", "colmater", "colonel", "combat", "comédie", "commande", "compact", "concert", "conduire", "confier", "congeler", "connoter", "consonne", "contact", "convexe", "copain", "copie", "corail", "corbeau", "cordage", "corniche", "corpus", "correct", "cortège", "cosmique", "costume", "coton", "coude", "coupure", "courage", "couteau", "couvrir", "coyote", "crabe", "crainte", "cravate", "crayon", "créature", "créditer", "crémeux", "creuser", "crevette", "cribler", "crier", "cristal", "critère", "croire", "croquer", "crotale", "crucial", "cruel", "crypter", "cubique", "cueillir", "cuillère", "cuisine", "cuivre", "culminer", "cultiver", "cumuler", "cupide", "curatif", "curseur", "cyanure", "cycle", "cylindre", "cynique", "daigner", "damier", "danger", "danseur", "dauphin", "débattre", "débiter", "déborder", "débrider", "débutant", "décaler", "décembre", "déchirer", "décider", "déclarer", "décorer", "décrire", "décupler", "dédale", "déductif", "déesse", "défensif", "défiler", "défrayer", "dégager", "dégivrer", "déglutir", "dégrafer", "déjeuner", "délice", "déloger", "demander", "demeurer", "démolir", "dénicher", "dénouer", "dentelle", "dénuder", "départ", "dépenser", "déphaser", "déplacer", "déposer", "déranger", "dérober", "désastre", "descente", "désert", "désigner", "désobéir", "dessiner", "destrier", "détacher", "détester", "détourer", "détresse", "devancer", "devenir", "deviner", "devoir", "diable", "dialogue", "diamant", "dicter", "différer", "digérer", "digital", "digne", "diluer", "dimanche", "diminuer", "dioxyde", "directif", "diriger", "discuter", "disposer", "dissiper", "distance", "divertir", "diviser", "docile", "docteur", "dogme", "doigt", "domaine", "domicile", "dompter", "donateur", "donjon", "donner", "dopamine", "dortoir", "dorure", "dosage", "doseur", "dossier", "dotation", "douanier", "double", "douceur", "douter", "doyen", "dragon", "draper", "dresser", "dribbler", "droiture", "duperie", "duplexe", "durable", "durcir", "dynastie", "éblouir", "écarter", "écharpe", "échelle", "éclairer", "éclipse", "éclore", "écluse", "école", "économie", "écorce", "écouter", "écraser", "écrémer", "écrivain", "écrou", "écume", "écureuil", "édifier", "éduquer", "effacer", "effectif", "effigie", "effort", "effrayer", "effusion", "égaliser", "égarer", "éjecter", "élaborer", "élargir", "électron", "élégant", "éléphant", "élève", "éligible", "élitisme", "éloge", "élucider", "éluder", "emballer", "embellir", "embryon", "émeraude", "émission", "emmener", "émotion", "émouvoir", "empereur", "employer", "emporter", "emprise", "émulsion", "encadrer", "enchère", "enclave", "encoche", "endiguer", "endosser", "endroit", "enduire", "énergie", "enfance", "enfermer", "enfouir", "engager", "engin", "englober", "énigme", "enjamber", "enjeu", "enlever", "ennemi", "ennuyeux", "enrichir", "enrobage", "enseigne", "entasser", "entendre", "entier", "entourer", "entraver", "énumérer", "envahir", "enviable", "envoyer", "enzyme", "éolien", "épaissir", "épargne", "épatant", "épaule", "épicerie", "épidémie", "épier", "épilogue", "épine", "épisode", "épitaphe", "époque", "épreuve", "éprouver", "épuisant", "équerre", "équipe", "ériger", "érosion", "erreur", "éruption", "escalier", "espadon", "espèce", "espiègle", "espoir", "esprit", "esquiver", "essayer", "essence", "essieu", "essorer", "estime", "estomac", "estrade", "étagère", "étaler", "étanche", "étatique", "éteindre", "étendoir", "éternel", "éthanol", "éthique", "ethnie", "étirer", "étoffer", "étoile", "étonnant", "étourdir", "étrange", "étroit", "étude", "euphorie", "évaluer", "évasion", "éventail", "évidence", "éviter", "évolutif", "évoquer", "exact", "exagérer", "exaucer", "exceller", "excitant", "exclusif", "excuse", "exécuter", "exemple", "exercer", "exhaler", "exhorter", "exigence", "exiler", "exister", "exotique", "expédier", "explorer", "exposer", "exprimer", "exquis", "extensif", "extraire", "exulter", "fable", "fabuleux", "facette", "facile", "facture", "faiblir", "falaise", "fameux", "famille", "farceur", "farfelu", "farine", "farouche", "fasciner", "fatal", "fatigue", "faucon", "fautif", "faveur", "favori", "fébrile", "féconder", "fédérer", "félin", "femme", "fémur", "fendoir", "féodal", "fermer", "féroce", "ferveur", "festival", "feuille", "feutre", "février", "fiasco", "ficeler", "fictif", "fidèle", "figure", "filature", "filetage", "filière", "filleul", "filmer", "filou", "filtrer", "financer", "finir", "fiole", "firme", "fissure", "fixer", "flairer", "flamme", "flasque", "flatteur", "fléau", "flèche", "fleur", "flexion", "flocon", "flore", "fluctuer", "fluide", "fluvial", "folie", "fonderie", "fongible", "fontaine", "forcer", "forgeron", "formuler", "fortune", "fossile", "foudre", "fougère", "fouiller", "foulure", "fourmi", "fragile", "fraise", "franchir", "frapper", "frayeur", "frégate", "freiner", "frelon", "frémir", "frénésie", "frère", "friable", "friction", "frisson", "frivole", "froid", "fromage", "frontal", "frotter", "fruit", "fugitif", "fuite", "fureur", "furieux", "furtif", "fusion", "futur", "gagner", "galaxie", "galerie", "gambader", "garantir", "gardien", "garnir", "garrigue", "gazelle", "gazon", "géant", "gélatine", "gélule", "gendarme", "général", "génie", "genou", "gentil", "géologie", "géomètre", "géranium", "germe", "gestuel", "geyser", "gibier", "gicler", "girafe", "givre", "glace", "glaive", "glisser", "globe", "gloire", "glorieux", "golfeur", "gomme", "gonfler", "gorge", "gorille", "goudron", "gouffre", "goulot", "goupille", "gourmand", "goutte", "graduel", "graffiti", "graine", "grand", "grappin", "gratuit", "gravir", "grenat", "griffure", "griller", "grimper", "grogner", "gronder", "grotte", "groupe", "gruger", "grutier", "gruyère", "guépard", "guerrier", "guide", "guimauve", "guitare", "gustatif", "gymnaste", "gyrostat", "habitude", "hachoir", "halte", "hameau", "hangar", "hanneton", "haricot", "harmonie", "harpon", "hasard", "hélium", "hématome", "herbe", "hérisson", "hermine", "héron", "hésiter", "heureux", "hiberner", "hibou", "hilarant", "histoire", "hiver", "homard", "hommage", "homogène", "honneur", "honorer", "honteux", "horde", "horizon", "horloge", "hormone", "horrible", "houleux", "housse", "hublot", "huileux", "humain", "humble", "humide", "humour", "hurler", "hydromel", "hygiène", "hymne", "hypnose", "idylle", "ignorer", "iguane", "illicite", "illusion", "image", "imbiber", "imiter", "immense", "immobile", "immuable", "impact", "impérial", "implorer", "imposer", "imprimer", "imputer", "incarner", "incendie", "incident", "incliner", "incolore", "indexer", "indice", "inductif", "inédit", "ineptie", "inexact", "infini", "infliger", "informer", "infusion", "ingérer", "inhaler", "inhiber", "injecter", "injure", "innocent", "inoculer", "inonder", "inscrire", "insecte", "insigne", "insolite", "inspirer", "instinct", "insulter", "intact", "intense", "intime", "intrigue", "intuitif", "inutile", "invasion", "inventer", "inviter", "invoquer", "ironique", "irradier", "irréel", "irriter", "isoler", "ivoire", "ivresse", "jaguar", "jaillir", "jambe", "janvier", "jardin", "jauger", "jaune", "javelot", "jetable", "jeton", "jeudi", "jeunesse", "joindre", "joncher", "jongler", "joueur", "jouissif", "journal", "jovial", "joyau", "joyeux", "jubiler", "jugement", "junior", "jupon", "juriste", "justice", "juteux", "juvénile", "kayak", "kimono", "kiosque", "label", "labial", "labourer", "lacérer", "lactose", "lagune", "laine", "laisser", "laitier", "lambeau", "lamelle", "lampe", "lanceur", "langage", "lanterne", "lapin", "largeur", "larme", "laurier", "lavabo", "lavoir", "lecture", "légal", "léger", "légume", "lessive", "lettre", "levier", "lexique", "lézard", "liasse", "libérer", "libre", "licence", "licorne", "liège", "lièvre", "ligature", "ligoter", "ligue", "limer", "limite", "limonade", "limpide", "linéaire", "lingot", "lionceau", "liquide", "lisière", "lister", "lithium", "litige", "littoral", "livreur", "logique", "lointain", "loisir", "lombric", "loterie", "louer", "lourd", "loutre", "louve", "loyal", "lubie", "lucide", "lucratif", "lueur", "lugubre", "luisant", "lumière", "lunaire", "lundi", "luron", "lutter", "luxueux", "machine", "magasin", "magenta", "magique", "maigre", "maillon", "maintien", "mairie", "maison", "majorer", "malaxer", "maléfice", "malheur", "malice", "mallette", "mammouth", "mandater", "maniable", "manquant", "manteau", "manuel", "marathon", "marbre", "marchand", "mardi", "maritime", "marqueur", "marron", "marteler", "mascotte", "massif", "matériel", "matière", "matraque", "maudire", "maussade", "mauve", "maximal", "méchant", "méconnu", "médaille", "médecin", "méditer", "méduse", "meilleur", "mélange", "mélodie", "membre", "mémoire", "menacer", "mener", "menhir", "mensonge", "mentor", "mercredi", "mérite", "merle", "messager", "mesure", "métal", "météore", "méthode", "métier", "meuble", "miauler", "microbe", "miette", "mignon", "migrer", "milieu", "million", "mimique", "mince", "minéral", "minimal", "minorer", "minute", "miracle", "miroiter", "missile", "mixte", "mobile", "moderne", "moelleux", "mondial", "moniteur", "monnaie", "monotone", "monstre", "montagne", "monument", "moqueur", "morceau", "morsure", "mortier", "moteur", "motif", "mouche", "moufle", "moulin", "mousson", "mouton", "mouvant", "multiple", "munition", "muraille", "murène", "murmure", "muscle", "muséum", "musicien", "mutation", "muter", "mutuel", "myriade", "myrtille", "mystère", "mythique", "nageur", "nappe", "narquois", "narrer", "natation", "nation", "nature", "naufrage", "nautique", "navire", "nébuleux", "nectar", "néfaste", "négation", "négliger", "négocier", "neige", "nerveux", "nettoyer", "neurone", "neutron", "neveu", "niche", "nickel", "nitrate", "niveau", "noble", "nocif", "nocturne", "noirceur", "noisette", "nomade", "nombreux", "nommer", "normatif", "notable", "notifier", "notoire", "nourrir", "nouveau", "novateur", "novembre", "novice", "nuage", "nuancer", "nuire", "nuisible", "numéro", "nuptial", "nuque", "nutritif", "obéir", "objectif", "obliger", "obscur", "observer", "obstacle", "obtenir", "obturer", "occasion", "occuper", "océan", "octobre", "octroyer", "octupler", "oculaire", "odeur", "odorant", "offenser", "officier", "offrir", "ogive", "oiseau", "oisillon", "olfactif", "olivier", "ombrage", "omettre", "onctueux", "onduler", "onéreux", "onirique", "opale", "opaque", "opérer", "opinion", "opportun", "opprimer", "opter", "optique", "orageux", "orange", "orbite", "ordonner", "oreille", "organe", "orgueil", "orifice", "ornement", "orque", "ortie", "osciller", "osmose", "ossature", "otarie", "ouragan", "ourson", "outil", "outrager", "ouvrage", "ovation", "oxyde", "oxygène", "ozone", "paisible", "palace", "palmarès", "palourde", "palper", "panache", "panda", "pangolin", "paniquer", "panneau", "panorama", "pantalon", "papaye", "papier", "papoter", "papyrus", "paradoxe", "parcelle", "paresse", "parfumer", "parler", "parole", "parrain", "parsemer", "partager", "parure", "parvenir", "passion", "pastèque", "paternel", "patience", "patron", "pavillon", "pavoiser", "payer", "paysage", "peigne", "peintre", "pelage", "pélican", "pelle", "pelouse", "peluche", "pendule", "pénétrer", "pénible", "pensif", "pénurie", "pépite", "péplum", "perdrix", "perforer", "période", "permuter", "perplexe", "persil", "perte", "peser", "pétale", "petit", "pétrir", "peuple", "pharaon", "phobie", "phoque", "photon", "phrase", "physique", "piano", "pictural", "pièce", "pierre", "pieuvre", "pilote", "pinceau", "pipette", "piquer", "pirogue", "piscine", "piston", "pivoter", "pixel", "pizza", "placard", "plafond", "plaisir", "planer", "plaque", "plastron", "plateau", "pleurer", "plexus", "pliage", "plomb", "plonger", "pluie", "plumage", "pochette", "poésie", "poète", "pointe", "poirier", "poisson", "poivre", "polaire", "policier", "pollen", "polygone", "pommade", "pompier", "ponctuel", "pondérer", "poney", "portique", "position", "posséder", "posture", "potager", "poteau", "potion", "pouce", "poulain", "poumon", "pourpre", "poussin", "pouvoir", "prairie", "pratique", "précieux", "prédire", "préfixe", "prélude", "prénom", "présence", "prétexte", "prévoir", "primitif", "prince", "prison", "priver", "problème", "procéder", "prodige", "profond", "progrès", "proie", "projeter", "prologue", "promener", "propre", "prospère", "protéger", "prouesse", "proverbe", "prudence", "pruneau", "psychose", "public", "puceron", "puiser", "pulpe", "pulsar", "punaise", "punitif", "pupitre", "purifier", "puzzle", "pyramide", "quasar", "querelle", "question", "quiétude", "quitter", "quotient", "racine", "raconter", "radieux", "ragondin", "raideur", "raisin", "ralentir", "rallonge", "ramasser", "rapide", "rasage", "ratisser", "ravager", "ravin", "rayonner", "réactif", "réagir", "réaliser", "réanimer", "recevoir", "réciter", "réclamer", "récolter", "recruter", "reculer", "recycler", "rédiger", "redouter", "refaire", "réflexe", "réformer", "refrain", "refuge", "régalien", "région", "réglage", "régulier", "réitérer", "rejeter", "rejouer", "relatif", "relever", "relief", "remarque", "remède", "remise", "remonter", "remplir", "remuer", "renard", "renfort", "renifler", "renoncer", "rentrer", "renvoi", "replier", "reporter", "reprise", "reptile", "requin", "réserve", "résineux", "résoudre", "respect", "rester", "résultat", "rétablir", "retenir", "réticule", "retomber", "retracer", "réunion", "réussir", "revanche", "revivre", "révolte", "révulsif", "richesse", "rideau", "rieur", "rigide", "rigoler", "rincer", "riposter", "risible", "risque", "rituel", "rival", "rivière", "rocheux", "romance", "rompre", "ronce", "rondin", "roseau", "rosier", "rotatif", "rotor", "rotule", "rouge", "rouille", "rouleau", "routine", "royaume", "ruban", "rubis", "ruche", "ruelle", "rugueux", "ruiner", "ruisseau", "ruser", "rustique", "rythme", "sabler", "saboter", "sabre", "sacoche", "safari", "sagesse", "saisir", "salade", "salive", "salon", "saluer", "samedi", "sanction", "sanglier", "sarcasme", "sardine", "saturer", "saugrenu", "saumon", "sauter", "sauvage", "savant", "savonner", "scalpel", "scandale", "scélérat", "scénario", "sceptre", "schéma", "science", "scinder", "score", "scrutin", "sculpter", "séance", "sécable", "sécher", "secouer", "sécréter", "sédatif", "séduire", "seigneur", "séjour", "sélectif", "semaine", "sembler", "semence", "séminal", "sénateur", "sensible", "sentence", "séparer", "séquence", "serein", "sergent", "sérieux", "serrure", "sérum", "service", "sésame", "sévir", "sevrage", "sextuple", "sidéral", "siècle", "siéger", "siffler", "sigle", "signal", "silence", "silicium", "simple", "sincère", "sinistre", "siphon", "sirop", "sismique", "situer", "skier", "social", "socle", "sodium", "soigneux", "soldat", "soleil", "solitude", "soluble", "sombre", "sommeil", "somnoler", "sonde", "songeur", "sonnette", "sonore", "sorcier", "sortir", "sosie", "sottise", "soucieux", "soudure", "souffle", "soulever", "soupape", "source", "soutirer", "souvenir", "spacieux", "spatial", "spécial", "sphère", "spiral", "stable", "station", "sternum", "stimulus", "stipuler", "strict", "studieux", "stupeur", "styliste", "sublime", "substrat", "subtil", "subvenir", "succès", "sucre", "suffixe", "suggérer", "suiveur", "sulfate", "superbe", "supplier", "surface", "suricate", "surmener", "surprise", "sursaut", "survie", "suspect", "syllabe", "symbole", "symétrie", "synapse", "syntaxe", "système", "tabac", "tablier", "tactile", "tailler", "talent", "talisman", "talonner", "tambour", "tamiser", "tangible", "tapis", "taquiner", "tarder", "tarif", "tartine", "tasse", "tatami", "tatouage", "taupe", "taureau", "taxer", "témoin", "temporel", "tenaille", "tendre", "teneur", "tenir", "tension", "terminer", "terne", "terrible", "tétine", "texte", "thème", "théorie", "thérapie", "thorax", "tibia", "tiède", "timide", "tirelire", "tiroir", "tissu", "titane", "titre", "tituber", "toboggan", "tolérant", "tomate", "tonique", "tonneau", "toponyme", "torche", "tordre", "tornade", "torpille", "torrent", "torse", "tortue", "totem", "toucher", "tournage", "tousser", "toxine", "traction", "trafic", "tragique", "trahir", "train", "trancher", "travail", "trèfle", "tremper", "trésor", "treuil", "triage", "tribunal", "tricoter", "trilogie", "triomphe", "tripler", "triturer", "trivial", "trombone", "tronc", "tropical", "troupeau", "tuile", "tulipe", "tumulte", "tunnel", "turbine", "tuteur", "tutoyer", "tuyau", "tympan", "typhon", "typique", "tyran", "ubuesque", "ultime", "ultrason", "unanime", "unifier", "union", "unique", "unitaire", "univers", "uranium", "urbain", "urticant", "usage", "usine", "usuel", "usure", "utile", "utopie", "vacarme", "vaccin", "vagabond", "vague", "vaillant", "vaincre", "vaisseau", "valable", "valise", "vallon", "valve", "vampire", "vanille", "vapeur", "varier", "vaseux", "vassal", "vaste", "vecteur", "vedette", "végétal", "véhicule", "veinard", "véloce", "vendredi", "vénérer", "venger", "venimeux", "ventouse", "verdure", "vérin", "vernir", "verrou", "verser", "vertu", "veston", "vétéran", "vétuste", "vexant", "vexer", "viaduc", "viande", "victoire", "vidange", "vidéo", "vignette", "vigueur", "vilain", "village", "vinaigre", "violon", "vipère", "virement", "virtuose", "virus", "visage", "viseur", "vision", "visqueux", "visuel", "vital", "vitesse", "viticole", "vitrine", "vivace", "vivipare", "vocation", "voguer", "voile", "voisin", "voiture", "volaille", "volcan", "voltiger", "volume", "vorace", "vortex", "voter", "vouloir", "voyage", "voyelle", "wagon", "xénon", "yacht", "zèbre", "zénith", "zeste", "zoologie"] static var italianWords: [String] = ["abaco", "abbaglio", "abbinato", "abete", "abisso", "abolire", "abrasivo", "abrogato", "accadere", "accenno", "accusato", "acetone", "achille", "acido", "acqua", "acre", "acrilico", "acrobata", "acuto", "adagio", "addebito", "addome", "adeguato", "aderire", "adipe", "adottare", "adulare", "affabile", "affetto", "affisso", "affranto", "aforisma", "afoso", "africano", "agave", "agente", "agevole", "aggancio", "agire", "agitare", "agonismo", "agricolo", "agrumeto", "aguzzo", "alabarda", "alato", "albatro", "alberato", "albo", "albume", "alce", "alcolico", "alettone", "alfa", "algebra", "aliante", "alibi", "alimento", "allagato", "allegro", "allievo", "allodola", "allusivo", "almeno", "alogeno", "alpaca", "alpestre", "altalena", "alterno", "alticcio", "altrove", "alunno", "alveolo", "alzare", "amalgama", "amanita", "amarena", "ambito", "ambrato", "ameba", "america", "ametista", "amico", "ammasso", "ammenda", "ammirare", "ammonito", "amore", "ampio", "ampliare", "amuleto", "anacardo", "anagrafe", "analista", "anarchia", "anatra", "anca", "ancella", "ancora", "andare", "andrea", "anello", "angelo", "angolare", "angusto", "anima", "annegare", "annidato", "anno", "annuncio", "anonimo", "anticipo", "anzi", "apatico", "apertura", "apode", "apparire", "appetito", "appoggio", "approdo", "appunto", "aprile", "arabica", "arachide", "aragosta", "araldica", "arancio", "aratura", "arazzo", "arbitro", "archivio", "ardito", "arenile", "argento", "argine", "arguto", "aria", "armonia", "arnese", "arredato", "arringa", "arrosto", "arsenico", "arso", "artefice", "arzillo", "asciutto", "ascolto", "asepsi", "asettico", "asfalto", "asino", "asola", "aspirato", "aspro", "assaggio", "asse", "assoluto", "assurdo", "asta", "astenuto", "astice", "astratto", "atavico", "ateismo", "atomico", "atono", "attesa", "attivare", "attorno", "attrito", "attuale", "ausilio", "austria", "autista", "autonomo", "autunno", "avanzato", "avere", "avvenire", "avviso", "avvolgere", "azione", "azoto", "azzimo", "azzurro", "babele", "baccano", "bacino", "baco", "badessa", "badilata", "bagnato", "baita", "balcone", "baldo", "balena", "ballata", "balzano", "bambino", "bandire", "baraonda", "barbaro", "barca", "baritono", "barlume", "barocco", "basilico", "basso", "batosta", "battuto", "baule", "bava", "bavosa", "becco", "beffa", "belgio", "belva", "benda", "benevole", "benigno", "benzina", "bere", "berlina", "beta", "bibita", "bici", "bidone", "bifido", "biga", "bilancia", "bimbo", "binocolo", "biologo", "bipede", "bipolare", "birbante", "birra", "biscotto", "bisesto", "bisnonno", "bisonte", "bisturi", "bizzarro", "blando", "blatta", "bollito", "bonifico", "bordo", "bosco", "botanico", "bottino", "bozzolo", "braccio", "bradipo", "brama", "branca", "bravura", "bretella", "brevetto", "brezza", "briglia", "brillante", "brindare", "broccolo", "brodo", "bronzina", "brullo", "bruno", "bubbone", "buca", "budino", "buffone", "buio", "bulbo", "buono", "burlone", "burrasca", "bussola", "busta", "cadetto", "caduco", "calamaro", "calcolo", "calesse", "calibro", "calmo", "caloria", "cambusa", "camerata", "camicia", "cammino", "camola", "campale", "canapa", "candela", "cane", "canino", "canotto", "cantina", "capace", "capello", "capitolo", "capogiro", "cappero", "capra", "capsula", "carapace", "carcassa", "cardo", "carisma", "carovana", "carretto", "cartolina", "casaccio", "cascata", "caserma", "caso", "cassone", "castello", "casuale", "catasta", "catena", "catrame", "cauto", "cavillo", "cedibile", "cedrata", "cefalo", "celebre", "cellulare", "cena", "cenone", "centesimo", "ceramica", "cercare", "certo", "cerume", "cervello", "cesoia", "cespo", "ceto", "chela", "chiaro", "chicca", "chiedere", "chimera", "china", "chirurgo", "chitarra", "ciao", "ciclismo", "cifrare", "cigno", "cilindro", "ciottolo", "circa", "cirrosi", "citrico", "cittadino", "ciuffo", "civetta", "civile", "classico", "clinica", "cloro", "cocco", "codardo", "codice", "coerente", "cognome", "collare", "colmato", "colore", "colposo", "coltivato", "colza", "coma", "cometa", "commando", "comodo", "computer", "comune", "conciso", "condurre", "conferma", "congelare", "coniuge", "connesso", "conoscere", "consumo", "continuo", "convegno", "coperto", "copione", "coppia", "copricapo", "corazza", "cordata", "coricato", "cornice", "corolla", "corpo", "corredo", "corsia", "cortese", "cosmico", "costante", "cottura", "covato", "cratere", "cravatta", "creato", "credere", "cremoso", "crescita", "creta", "criceto", "crinale", "crisi", "critico", "croce", "cronaca", "crostata", "cruciale", "crusca", "cucire", "cuculo", "cugino", "cullato", "cupola", "curatore", "cursore", "curvo", "cuscino", "custode", "dado", "daino", "dalmata", "damerino", "daniela", "dannoso", "danzare", "datato", "davanti", "davvero", "debutto", "decennio", "deciso", "declino", "decollo", "decreto", "dedicato", "definito", "deforme", "degno", "delegare", "delfino", "delirio", "delta", "demenza", "denotato", "dentro", "deposito", "derapata", "derivare", "deroga", "descritto", "deserto", "desiderio", "desumere", "detersivo", "devoto", "diametro", "dicembre", "diedro", "difeso", "diffuso", "digerire", "digitale", "diluvio", "dinamico", "dinnanzi", "dipinto", "diploma", "dipolo", "diradare", "dire", "dirotto", "dirupo", "disagio", "discreto", "disfare", "disgelo", "disposto", "distanza", "disumano", "dito", "divano", "divelto", "dividere", "divorato", "doblone", "docente", "doganale", "dogma", "dolce", "domato", "domenica", "dominare", "dondolo", "dono", "dormire", "dote", "dottore", "dovuto", "dozzina", "drago", "druido", "dubbio", "dubitare", "ducale", "duna", "duomo", "duplice", "duraturo", "ebano", "eccesso", "ecco", "eclissi", "economia", "edera", "edicola", "edile", "editoria", "educare", "egemonia", "egli", "egoismo", "egregio", "elaborato", "elargire", "elegante", "elencato", "eletto", "elevare", "elfico", "elica", "elmo", "elsa", "eluso", "emanato", "emblema", "emesso", "emiro", "emotivo", "emozione", "empirico", "emulo", "endemico", "enduro", "energia", "enfasi", "enoteca", "entrare", "enzima", "epatite", "epilogo", "episodio", "epocale", "eppure", "equatore", "erario", "erba", "erboso", "erede", "eremita", "erigere", "ermetico", "eroe", "erosivo", "errante", "esagono", "esame", "esanime", "esaudire", "esca", "esempio", "esercito", "esibito", "esigente", "esistere", "esito", "esofago", "esortato", "esoso", "espanso", "espresso", "essenza", "esso", "esteso", "estimare", "estonia", "estroso", "esultare", "etilico", "etnico", "etrusco", "etto", "euclideo", "europa", "evaso", "evidenza", "evitato", "evoluto", "evviva", "fabbrica", "faccenda", "fachiro", "falco", "famiglia", "fanale", "fanfara", "fango", "fantasma", "fare", "farfalla", "farinoso", "farmaco", "fascia", "fastoso", "fasullo", "faticare", "fato", "favoloso", "febbre", "fecola", "fede", "fegato", "felpa", "feltro", "femmina", "fendere", "fenomeno", "fermento", "ferro", "fertile", "fessura", "festivo", "fetta", "feudo", "fiaba", "fiducia", "fifa", "figurato", "filo", "finanza", "finestra", "finire", "fiore", "fiscale", "fisico", "fiume", "flacone", "flamenco", "flebo", "flemma", "florido", "fluente", "fluoro", "fobico", "focaccia", "focoso", "foderato", "foglio", "folata", "folclore", "folgore", "fondente", "fonetico", "fonia", "fontana", "forbito", "forchetta", "foresta", "formica", "fornaio", "foro", "fortezza", "forzare", "fosfato", "fosso", "fracasso", "frana", "frassino", "fratello", "freccetta", "frenata", "fresco", "frigo", "frollino", "fronde", "frugale", "frutta", "fucilata", "fucsia", "fuggente", "fulmine", "fulvo", "fumante", "fumetto", "fumoso", "fune", "funzione", "fuoco", "furbo", "furgone", "furore", "fuso", "futile", "gabbiano", "gaffe", "galateo", "gallina", "galoppo", "gambero", "gamma", "garanzia", "garbo", "garofano", "garzone", "gasdotto", "gasolio", "gastrico", "gatto", "gaudio", "gazebo", "gazzella", "geco", "gelatina", "gelso", "gemello", "gemmato", "gene", "genitore", "gennaio", "genotipo", "gergo", "ghepardo", "ghiaccio", "ghisa", "giallo", "gilda", "ginepro", "giocare", "gioiello", "giorno", "giove", "girato", "girone", "gittata", "giudizio", "giurato", "giusto", "globulo", "glutine", "gnomo", "gobba", "golf", "gomito", "gommone", "gonfio", "gonna", "governo", "gracile", "grado", "grafico", "grammo", "grande", "grattare", "gravoso", "grazia", "greca", "gregge", "grifone", "grigio", "grinza", "grotta", "gruppo", "guadagno", "guaio", "guanto", "guardare", "gufo", "guidare", "ibernato", "icona", "identico", "idillio", "idolo", "idra", "idrico", "idrogeno", "igiene", "ignaro", "ignorato", "ilare", "illeso", "illogico", "illudere", "imballo", "imbevuto", "imbocco", "imbuto", "immane", "immerso", "immolato", "impacco", "impeto", "impiego", "importo", "impronta", "inalare", "inarcare", "inattivo", "incanto", "incendio", "inchino", "incisivo", "incluso", "incontro", "incrocio", "incubo", "indagine", "india", "indole", "inedito", "infatti", "infilare", "inflitto", "ingaggio", "ingegno", "inglese", "ingordo", "ingrosso", "innesco", "inodore", "inoltrare", "inondato", "insano", "insetto", "insieme", "insonnia", "insulina", "intasato", "intero", "intonaco", "intuito", "inumidire", "invalido", "invece", "invito", "iperbole", "ipnotico", "ipotesi", "ippica", "iride", "irlanda", "ironico", "irrigato", "irrorare", "isolato", "isotopo", "isterico", "istituto", "istrice", "italia", "iterare", "labbro", "labirinto", "lacca", "lacerato", "lacrima", "lacuna", "laddove", "lago", "lampo", "lancetta", "lanterna", "lardoso", "larga", "laringe", "lastra", "latenza", "latino", "lattuga", "lavagna", "lavoro", "legale", "leggero", "lembo", "lentezza", "lenza", "leone", "lepre", "lesivo", "lessato", "lesto", "letterale", "leva", "levigato", "libero", "lido", "lievito", "lilla", "limatura", "limitare", "limpido", "lineare", "lingua", "liquido", "lira", "lirica", "lisca", "lite", "litigio", "livrea", "locanda", "lode", "logica", "lombare", "londra", "longevo", "loquace", "lorenzo", "loto", "lotteria", "luce", "lucidato", "lumaca", "luminoso", "lungo", "lupo", "luppolo", "lusinga", "lusso", "lutto", "macabro", "macchina", "macero", "macinato", "madama", "magico", "maglia", "magnete", "magro", "maiolica", "malafede", "malgrado", "malinteso", "malsano", "malto", "malumore", "mana", "mancia", "mandorla", "mangiare", "manifesto", "mannaro", "manovra", "mansarda", "mantide", "manubrio", "mappa", "maratona", "marcire", "maretta", "marmo", "marsupio", "maschera", "massaia", "mastino", "materasso", "matricola", "mattone", "maturo", "mazurca", "meandro", "meccanico", "mecenate", "medesimo", "meditare", "mega", "melassa", "melis", "melodia", "meninge", "meno", "mensola", "mercurio", "merenda", "merlo", "meschino", "mese", "messere", "mestolo", "metallo", "metodo", "mettere", "miagolare", "mica", "micelio", "michele", "microbo", "midollo", "miele", "migliore", "milano", "milite", "mimosa", "minerale", "mini", "minore", "mirino", "mirtillo", "miscela", "missiva", "misto", "misurare", "mitezza", "mitigare", "mitra", "mittente", "mnemonico", "modello", "modifica", "modulo", "mogano", "mogio", "mole", "molosso", "monastero", "monco", "mondina", "monetario", "monile", "monotono", "monsone", "montato", "monviso", "mora", "mordere", "morsicato", "mostro", "motivato", "motosega", "motto", "movenza", "movimento", "mozzo", "mucca", "mucosa", "muffa", "mughetto", "mugnaio", "mulatto", "mulinello", "multiplo", "mummia", "munto", "muovere", "murale", "musa", "muscolo", "musica", "mutevole", "muto", "nababbo", "nafta", "nanometro", "narciso", "narice", "narrato", "nascere", "nastrare", "naturale", "nautica", "naviglio", "nebulosa", "necrosi", "negativo", "negozio", "nemmeno", "neofita", "neretto", "nervo", "nessuno", "nettuno", "neutrale", "neve", "nevrotico", "nicchia", "ninfa", "nitido", "nobile", "nocivo", "nodo", "nome", "nomina", "nordico", "normale", "norvegese", "nostrano", "notare", "notizia", "notturno", "novella", "nucleo", "nulla", "numero", "nuovo", "nutrire", "nuvola", "nuziale", "oasi", "obbedire", "obbligo", "obelisco", "oblio", "obolo", "obsoleto", "occasione", "occhio", "occidente", "occorrere", "occultare", "ocra", "oculato", "odierno", "odorare", "offerta", "offrire", "offuscato", "oggetto", "oggi", "ognuno", "olandese", "olfatto", "oliato", "oliva", "ologramma", "oltre", "omaggio", "ombelico", "ombra", "omega", "omissione", "ondoso", "onere", "onice", "onnivoro", "onorevole", "onta", "operato", "opinione", "opposto", "oracolo", "orafo", "ordine", "orecchino", "orefice", "orfano", "organico", "origine", "orizzonte", "orma", "ormeggio", "ornativo", "orologio", "orrendo", "orribile", "ortensia", "ortica", "orzata", "orzo", "osare", "oscurare", "osmosi", "ospedale", "ospite", "ossa", "ossidare", "ostacolo", "oste", "otite", "otre", "ottagono", "ottimo", "ottobre", "ovale", "ovest", "ovino", "oviparo", "ovocito", "ovunque", "ovviare", "ozio", "pacchetto", "pace", "pacifico", "padella", "padrone", "paese", "paga", "pagina", "palazzina", "palesare", "pallido", "palo", "palude", "pandoro", "pannello", "paolo", "paonazzo", "paprica", "parabola", "parcella", "parere", "pargolo", "pari", "parlato", "parola", "partire", "parvenza", "parziale", "passivo", "pasticca", "patacca", "patologia", "pattume", "pavone", "peccato", "pedalare", "pedonale", "peggio", "peloso", "penare", "pendice", "penisola", "pennuto", "penombra", "pensare", "pentola", "pepe", "pepita", "perbene", "percorso", "perdonato", "perforare", "pergamena", "periodo", "permesso", "perno", "perplesso", "persuaso", "pertugio", "pervaso", "pesatore", "pesista", "peso", "pestifero", "petalo", "pettine", "petulante", "pezzo", "piacere", "pianta", "piattino", "piccino", "picozza", "piega", "pietra", "piffero", "pigiama", "pigolio", "pigro", "pila", "pilifero", "pillola", "pilota", "pimpante", "pineta", "pinna", "pinolo", "pioggia", "piombo", "piramide", "piretico", "pirite", "pirolisi", "pitone", "pizzico", "placebo", "planare", "plasma", "platano", "plenario", "pochezza", "poderoso", "podismo", "poesia", "poggiare", "polenta", "poligono", "pollice", "polmonite", "polpetta", "polso", "poltrona", "polvere", "pomice", "pomodoro", "ponte", "popoloso", "porfido", "poroso", "porpora", "porre", "portata", "posa", "positivo", "possesso", "postulato", "potassio", "potere", "pranzo", "prassi", "pratica", "precluso", "predica", "prefisso", "pregiato", "prelievo", "premere", "prenotare", "preparato", "presenza", "pretesto", "prevalso", "prima", "principe", "privato", "problema", "procura", "produrre", "profumo", "progetto", "prolunga", "promessa", "pronome", "proposta", "proroga", "proteso", "prova", "prudente", "prugna", "prurito", "psiche", "pubblico", "pudica", "pugilato", "pugno", "pulce", "pulito", "pulsante", "puntare", "pupazzo", "pupilla", "puro", "quadro", "qualcosa", "quasi", "querela", "quota", "raccolto", "raddoppio", "radicale", "radunato", "raffica", "ragazzo", "ragione", "ragno", "ramarro", "ramingo", "ramo", "randagio", "rantolare", "rapato", "rapina", "rappreso", "rasatura", "raschiato", "rasente", "rassegna", "rastrello", "rata", "ravveduto", "reale", "recepire", "recinto", "recluta", "recondito", "recupero", "reddito", "redimere", "regalato", "registro", "regola", "regresso", "relazione", "remare", "remoto", "renna", "replica", "reprimere", "reputare", "resa", "residente", "responso", "restauro", "rete", "retina", "retorica", "rettifica", "revocato", "riassunto", "ribadire", "ribelle", "ribrezzo", "ricarica", "ricco", "ricevere", "riciclato", "ricordo", "ricreduto", "ridicolo", "ridurre", "rifasare", "riflesso", "riforma", "rifugio", "rigare", "rigettato", "righello", "rilassato", "rilevato", "rimanere", "rimbalzo", "rimedio", "rimorchio", "rinascita", "rincaro", "rinforzo", "rinnovo", "rinomato", "rinsavito", "rintocco", "rinuncia", "rinvenire", "riparato", "ripetuto", "ripieno", "riportare", "ripresa", "ripulire", "risata", "rischio", "riserva", "risibile", "riso", "rispetto", "ristoro", "risultato", "risvolto", "ritardo", "ritegno", "ritmico", "ritrovo", "riunione", "riva", "riverso", "rivincita", "rivolto", "rizoma", "roba", "robotico", "robusto", "roccia", "roco", "rodaggio", "rodere", "roditore", "rogito", "rollio", "romantico", "rompere", "ronzio", "rosolare", "rospo", "rotante", "rotondo", "rotula", "rovescio", "rubizzo", "rubrica", "ruga", "rullino", "rumine", "rumoroso", "ruolo", "rupe", "russare", "rustico", "sabato", "sabbiare", "sabotato", "sagoma", "salasso", "saldatura", "salgemma", "salivare", "salmone", "salone", "saltare", "saluto", "salvo", "sapere", "sapido", "saporito", "saraceno", "sarcasmo", "sarto", "sassoso", "satellite", "satira", "satollo", "saturno", "savana", "savio", "saziato", "sbadiglio", "sbalzo", "sbancato", "sbarra", "sbattere", "sbavare", "sbendare", "sbirciare", "sbloccato", "sbocciato", "sbrinare", "sbruffone", "sbuffare", "scabroso", "scadenza", "scala", "scambiare", "scandalo", "scapola", "scarso", "scatenare", "scavato", "scelto", "scenico", "scettro", "scheda", "schiena", "sciarpa", "scienza", "scindere", "scippo", "sciroppo", "scivolo", "sclerare", "scodella", "scolpito", "scomparto", "sconforto", "scoprire", "scorta", "scossone", "scozzese", "scriba", "scrollare", "scrutinio", "scuderia", "scultore", "scuola", "scuro", "scusare", "sdebitare", "sdoganare", "seccatura", "secondo", "sedano", "seggiola", "segnalato", "segregato", "seguito", "selciato", "selettivo", "sella", "selvaggio", "semaforo", "sembrare", "seme", "seminato", "sempre", "senso", "sentire", "sepolto", "sequenza", "serata", "serbato", "sereno", "serio", "serpente", "serraglio", "servire", "sestina", "setola", "settimana", "sfacelo", "sfaldare", "sfamato", "sfarzoso", "sfaticato", "sfera", "sfida", "sfilato", "sfinge", "sfocato", "sfoderare", "sfogo", "sfoltire", "sforzato", "sfratto", "sfruttato", "sfuggito", "sfumare", "sfuso", "sgabello", "sgarbato", "sgonfiare", "sgorbio", "sgrassato", "sguardo", "sibilo", "siccome", "sierra", "sigla", "signore", "silenzio", "sillaba", "simbolo", "simpatico", "simulato", "sinfonia", "singolo", "sinistro", "sino", "sintesi", "sinusoide", "sipario", "sisma", "sistole", "situato", "slitta", "slogatura", "sloveno", "smarrito", "smemorato", "smentito", "smeraldo", "smilzo", "smontare", "smottato", "smussato", "snellire", "snervato", "snodo", "sobbalzo", "sobrio", "soccorso", "sociale", "sodale", "soffitto", "sogno", "soldato", "solenne", "solido", "sollazzo", "solo", "solubile", "solvente", "somatico", "somma", "sonda", "sonetto", "sonnifero", "sopire", "soppeso", "sopra", "sorgere", "sorpasso", "sorriso", "sorso", "sorteggio", "sorvolato", "sospiro", "sosta", "sottile", "spada", "spalla", "spargere", "spatola", "spavento", "spazzola", "specie", "spedire", "spegnere", "spelatura", "speranza", "spessore", "spettrale", "spezzato", "spia", "spigoloso", "spillato", "spinoso", "spirale", "splendido", "sportivo", "sposo", "spranga", "sprecare", "spronato", "spruzzo", "spuntino", "squillo", "sradicare", "srotolato", "stabile", "stacco", "staffa", "stagnare", "stampato", "stantio", "starnuto", "stasera", "statuto", "stelo", "steppa", "sterzo", "stiletto", "stima", "stirpe", "stivale", "stizzoso", "stonato", "storico", "strappo", "stregato", "stridulo", "strozzare", "strutto", "stuccare", "stufo", "stupendo", "subentro", "succoso", "sudore", "suggerito", "sugo", "sultano", "suonare", "superbo", "supporto", "surgelato", "surrogato", "sussurro", "sutura", "svagare", "svedese", "sveglio", "svelare", "svenuto", "svezia", "sviluppo", "svista", "svizzera", "svolta", "svuotare", "tabacco", "tabulato", "tacciare", "taciturno", "tale", "talismano", "tampone", "tannino", "tara", "tardivo", "targato", "tariffa", "tarpare", "tartaruga", "tasto", "tattico", "taverna", "tavolata", "tazza", "teca", "tecnico", "telefono", "temerario", "tempo", "temuto", "tendone", "tenero", "tensione", "tentacolo", "teorema", "terme", "terrazzo", "terzetto", "tesi", "tesserato", "testato", "tetro", "tettoia", "tifare", "tigella", "timbro", "tinto", "tipico", "tipografo", "tiraggio", "tiro", "titanio", "titolo", "titubante", "tizio", "tizzone", "toccare", "tollerare", "tolto", "tombola", "tomo", "tonfo", "tonsilla", "topazio", "topologia", "toppa", "torba", "tornare", "torrone", "tortora", "toscano", "tossire", "tostatura", "totano", "trabocco", "trachea", "trafila", "tragedia", "tralcio", "tramonto", "transito", "trapano", "trarre", "trasloco", "trattato", "trave", "treccia", "tremolio", "trespolo", "tributo", "tricheco", "trifoglio", "trillo", "trincea", "trio", "tristezza", "triturato", "trivella", "tromba", "trono", "troppo", "trottola", "trovare", "truccato", "tubatura", "tuffato", "tulipano", "tumulto", "tunisia", "turbare", "turchino", "tuta", "tutela", "ubicato", "uccello", "uccisore", "udire", "uditivo", "uffa", "ufficio", "uguale", "ulisse", "ultimato", "umano", "umile", "umorismo", "uncinetto", "ungere", "ungherese", "unicorno", "unificato", "unisono", "unitario", "unte", "uovo", "upupa", "uragano", "urgenza", "urlo", "usanza", "usato", "uscito", "usignolo", "usuraio", "utensile", "utilizzo", "utopia", "vacante", "vaccinato", "vagabondo", "vagliato", "valanga", "valgo", "valico", "valletta", "valoroso", "valutare", "valvola", "vampata", "vangare", "vanitoso", "vano", "vantaggio", "vanvera", "vapore", "varano", "varcato", "variante", "vasca", "vedetta", "vedova", "veduto", "vegetale", "veicolo", "velcro", "velina", "velluto", "veloce", "venato", "vendemmia", "vento", "verace", "verbale", "vergogna", "verifica", "vero", "verruca", "verticale", "vescica", "vessillo", "vestale", "veterano", "vetrina", "vetusto", "viandante", "vibrante", "vicenda", "vichingo", "vicinanza", "vidimare", "vigilia", "vigneto", "vigore", "vile", "villano", "vimini", "vincitore", "viola", "vipera", "virgola", "virologo", "virulento", "viscoso", "visione", "vispo", "vissuto", "visura", "vita", "vitello", "vittima", "vivanda", "vivido", "viziare", "voce", "voga", "volatile", "volere", "volpe", "voragine", "vulcano", "zampogna", "zanna", "zappato", "zattera", "zavorra", "zefiro", "zelante", "zelo", "zenzero", "zerbino", "zibetto", "zinco", "zircone", "zitto", "zolla", "zotico", "zucchero", "zufolo", "zulu", "zuppa"] } ================================================ FILE: HDWalletKit/Models/Account.swift ================================================ // // Account.swift // HDWalletKit // // Created by Pavlo Boiko on 04.07.18. // import Foundation public struct Account { public init(privateKey: PrivateKey) { self.privateKey = privateKey } public let privateKey: PrivateKey public var rawPrivateKey: String { return privateKey.get() } public var rawPublicKey: String { return privateKey.publicKey.get() } public var address: String { return privateKey.publicKey.address } } ================================================ FILE: HDWalletKit/Wallet/AccountBased/ERC20/ERC20.swift ================================================ // // ERC20.swift // HDWalletKit // // Created by Pavlo Boiko on 24.09.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public struct ERC20 { public let contractAddress: String public let decimal: Int public let symbol: String /// Initializer /// /// - Parameters: /// - contractAddress: contract address of this erc20 token /// - decimal: decimal specified in a contract /// - symbol: symbol of this erc20 token public init(contractAddress: String, decimal: Int, symbol: String) { self.contractAddress = contractAddress self.decimal = decimal self.symbol = symbol } /// Transfer method signiture /// function transfer(address _to, uint256 _value) returns (bool success) var transferSignature: Data { let method = "transfer(address,uint256)" return method.data(using: .ascii)!.sha3(.keccak256)[0...3] } var balanceSignature: Data { let method = "balanceOf(address)" return method.data(using: .ascii)!.sha3(.keccak256)[0...3] } /// Length of 256 bits private var lengthOf256bits: Int { return 256 / 4 } /// Generate transaction data for ERC20 token /// /// - Parameter: /// - toAddress: address you are transfering to /// - amount: amount to send /// - Returns: transaction data public func generateSendBalanceParameter(toAddress: String, amount: String) throws -> Data { let method = transferSignature.toHexString() let address = pad(string: toAddress.stripHexPrefix()) let poweredAmount = try power(amount: amount) let amount = pad(string: poweredAmount.serialize().toHexString()) return Data(hex: method + address + amount) } /// Generate get balance data for ERC20 token /// /// - Parameter: /// - toAddress: address you are transfering to /// - amount: amount to send /// - Returns: transaction data public func generateGetBalanceParameter(toAddress: String) throws -> Data { let method = balanceSignature.toHexString() let address = pad(string: toAddress.stripHexPrefix()) return Data(hex: method + address) } /// Power the amount by the decimal /// /// - Parameter: /// - amount: amount in string format /// - Returns: BigInt value powered by (10 * decimal) private func power(amount: String) throws -> BInt { let components = amount.split(separator: ".") // components.count must be 1 or 2. this method accepts only integer or decimal value // like 1, 10, 100 or 1.15, 10.7777, 19.9999 guard components.count == 1 || components.count == 2 else { throw HDWalletKitError.contractError(.containsInvalidCharactor(amount)) } guard let integer = BInt(String(components[0]), radix: 10) else { throw HDWalletKitError.contractError(.containsInvalidCharactor(amount)) } let poweredInteger = integer * (BInt(10) ** decimal) if components.count == 2 { let count = components[1].count guard count <= decimal else { throw HDWalletKitError.contractError(.invalidDecimalValue(amount)) } guard let digit = BInt(String(components[1]), radix: 10) else { throw HDWalletKitError.contractError(.containsInvalidCharactor(amount)) } let poweredDigit = digit * (BInt(10) ** (decimal - count)) return poweredInteger + poweredDigit } else { return poweredInteger } } /// Pad left spaces out of 256bits with 0 private func pad(string: String) -> String { var string = string while string.count != lengthOf256bits { string = "0" + string } return string } } ================================================ FILE: HDWalletKit/Wallet/AccountBased/Ethereum/Model/EthereumAddress.swift ================================================ // // Address.swift // HDWalletKit // // Created by Pavlo Boiko on 12.07.18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation /// Represents an address public struct EthereumAddress: Codable { /// Address in data format public let data: Data /// Address in string format, EIP55 encoded public let string: String public init(data: Data, string: String) { self.data = data self.string = string } public init(data: Data) { self.data = data self.string = "0x" + EIP55.encode(data) } public init(string: String) { self.data = Data(hex: string.stripHexPrefix()) self.string = string } } ================================================ FILE: HDWalletKit/Wallet/AccountBased/Ethereum/Model/EthereumRawTransaction.swift ================================================ import Foundation /// RawTransaction constructs necessary information to publish transaction. public struct EthereumRawTransaction { /// Amount value to send, unit is in Wei public let value: Wei /// Address to send ether to public let to: EthereumAddress /// Gas price for this transaction, unit is in Wei /// you need to convert it if it is specified in GWei /// use Converter.toWei method to convert GWei value to Wei public let gasPrice: Int /// Gas limit for this transaction /// Total amount of gas will be (gas price * gas limit) public let gasLimit: Int /// Nonce of your address public let nonce: Int /// Data to attach to this transaction public let data: Data public init(value: Wei, to: String, gasPrice: Int, gasLimit: Int, nonce: Int, data: Data = Data()) { self.value = value self.to = EthereumAddress(string:to) self.gasPrice = gasPrice self.gasLimit = gasLimit self.nonce = nonce self.data = data } } ================================================ FILE: HDWalletKit/Wallet/Coin.swift ================================================ // // Coin.swift // HDWalletKit // // Created by Pavlo Boiko on 10/3/18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public enum Coin { case bitcoin case ethereum case litecoin case bitcoinCash case dash case dogecoin //https://github.com/satoshilabs/slips/blob/master/slip-0132.md public var privateKeyVersion: UInt32 { switch self { case .litecoin: return 0x019D9CFE case .bitcoinCash: fallthrough case .bitcoin: return 0x0488ADE4 case .dash: return 0x02FE52CC case .dogecoin: return 0x0488E1F4 default: fatalError("Not implemented") } } // P2PKH public var publicKeyHash: UInt8 { switch self { case .litecoin: return 0x30 case .bitcoinCash: fallthrough case .bitcoin: return 0x00 case .dash: return 0x4C case .dogecoin: return 0x1E default: fatalError("Not implemented") } } // P2SH public var scriptHash: UInt8 { switch self { case .bitcoinCash: fallthrough case .litecoin: fallthrough case .bitcoin: return 0x05 case .dash: return 0x10 case .dogecoin: return 0x16 default: fatalError("Not implemented") } } //https://www.reddit.com/r/litecoin/comments/6vc8tc/how_do_i_convert_a_raw_private_key_to_wif_for/ public var wifAddressPrefix: UInt8 { switch self { case .dogecoin: return 0x9E case .bitcoinCash: fallthrough case .bitcoin: return 0x80 case .litecoin: return 0xB0 case .dash: return 0xCC default: fatalError("Not implemented") } } public var addressPrefix:String { switch self { case .ethereum: return "0x" default: return "" } } public var uncompressedPkSuffix: UInt8 { return 0x01 } public var coinType: UInt32 { switch self { case .bitcoin: return 0 case .litecoin: return 2 case .dash: return 5 case .dogecoin: return 3 case .ethereum: return 60 case .bitcoinCash: return 145 } } public var scheme: String { switch self { case .bitcoin: return "bitcoin" case .litecoin: return "litecoin" case .bitcoinCash: return "bitcoincash" case .dogecoin: return "dogecoin" case .dash: return "dash" default: return "" } } } ================================================ FILE: HDWalletKit/Wallet/PrivateKey.swift ================================================ // // PrivateKey.swift // HDWalletKit // // Created by Pavlo Boiko on 10/4/18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation enum PrivateKeyType { case hd case nonHd } public struct PrivateKey { public let raw: Data public let chainCode: Data public let index: UInt32 public let coin: Coin private var keyType: PrivateKeyType public init(seed: Data, coin: Coin) { let output = Crypto.HMACSHA512(key: "Bitcoin seed".data(using: .ascii)!, data: seed) self.raw = output[0..<32] self.chainCode = output[32..<64] self.index = 0 self.coin = coin self.keyType = .hd } public init?(pk: String, coin: Coin) { switch coin { case .ethereum: self.raw = Data(hex: pk) default: let utxoPkType = UtxoPrivateKeyType.pkType(for: pk, coin: coin) switch utxoPkType { case .some(let pkType): switch pkType { case .hex: self.raw = Data(hex: pk) case .wifUncompressed: let decodedPk = Base58.decode(pk) ?? Data() let wifData = decodedPk.dropLast(4).dropFirst() self.raw = wifData case .wifCompressed: let decodedPk = Base58.decode(pk) ?? Data() let wifData = decodedPk.dropLast(4).dropFirst().dropLast() self.raw = wifData } case .none: return nil } } self.chainCode = Data(capacity: 32) self.index = 0 self.coin = coin self.keyType = .nonHd } private init(privateKey: Data, chainCode: Data, index: UInt32, coin: Coin) { self.raw = privateKey self.chainCode = chainCode self.index = index self.coin = coin self.keyType = .hd } public var publicKey: PublicKey { return PublicKey(privateKey: raw, coin: coin) } public func wifCompressed() -> String { var data = Data() data += coin.wifAddressPrefix data += raw data += UInt8(0x01) data += data.doubleSHA256.prefix(4) return Base58.encode(data) } public func wifUncompressed() -> String { var data = Data() data += coin.wifAddressPrefix data += raw data += data.doubleSHA256.prefix(4) return Base58.encode(data) } public func get() -> String { switch self.coin { case .bitcoin: fallthrough case .litecoin: fallthrough case .dash: fallthrough case .bitcoinCash: return self.wifCompressed() case .dogecoin: return self.wifUncompressed() case .ethereum: return self.raw.toHexString() } } public func derived(at node:DerivationNode) -> PrivateKey { guard keyType == .hd else { fatalError() } let edge: UInt32 = 0x80000000 guard (edge & node.index) == 0 else { fatalError("Invalid child index") } var data = Data() switch node { case .hardened: data += UInt8(0) data += raw case .notHardened: data += Crypto.generatePublicKey(data: raw, compressed: true) } let derivingIndex = CFSwapInt32BigToHost(node.hardens ? (edge | node.index) : node.index) data += derivingIndex let digest = Crypto.HMACSHA512(key: chainCode, data: data) let factor = BInt(data: digest[0..<32]) let curveOrder = BInt(hex: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")! let derivedPrivateKey = ((BInt(data: raw) + factor) % curveOrder).data let derivedChainCode = digest[32..<64] return PrivateKey( privateKey: derivedPrivateKey, chainCode: derivedChainCode, index: derivingIndex, coin: coin ) } public func sign(hash: Data) throws -> Data { return try Crypto.sign(hash, privateKey: raw) } } ================================================ FILE: HDWalletKit/Wallet/PublicKey.swift ================================================ // // PublicKey.swift // HDWalletKit // // Created by Pavlo Boiko on 10/4/18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation import CryptoSwift import secp256k1 public struct PublicKey { public let compressedPublicKey: Data public let uncompressedPublicKey: Data public let coin: Coin public init(privateKey: Data, coin: Coin) { self.compressedPublicKey = Crypto.generatePublicKey(data: privateKey, compressed: true) self.uncompressedPublicKey = Crypto.generatePublicKey(data: privateKey, compressed: false) self.coin = coin } public init(base58: Data, coin: Coin) { let publickKey = Base58.encode(base58) self.compressedPublicKey = Data(hex: publickKey) self.uncompressedPublicKey = Data(hex: publickKey) self.coin = coin } // NOTE: https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki public var address: String { switch coin { case .dogecoin: fallthrough case .bitcoin: fallthrough case .dash: fallthrough case .bitcoinCash: fallthrough case .litecoin: return generateBtcAddress() case .ethereum: return generateEthAddress() } } public var utxoAddress: Address { switch coin { case .bitcoin, .litecoin, .dash, .bitcoinCash, .dogecoin: return try! LegacyAddress(address, coin: coin) case .ethereum: fatalError("Coin does not support UTXO address") } } func generateBtcAddress() -> String { let prefix = Data([coin.publicKeyHash]) let payload = RIPEMD160.hash(compressedPublicKey.sha256()) let checksum = (prefix + payload).doubleSHA256.prefix(4) return Base58.encode(prefix + payload + checksum) } func generateCashAddress() -> String { let prefix = Data([coin.publicKeyHash]) let payload = RIPEMD160.hash(compressedPublicKey.sha256()) return Bech32.encode(prefix + payload, prefix: coin.scheme) } func generateEthAddress() -> String { let formattedData = (Data(hex: coin.addressPrefix) + uncompressedPublicKey).dropFirst() let addressData = Crypto.sha3keccak256(data: formattedData).suffix(20) return coin.addressPrefix + EIP55.encode(addressData) } public func get() -> String { return compressedPublicKey.toHexString() } public var data: Data { return Data(hex: get()) } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Bitcoin/BitcoinAddress.swift ================================================ // // BitcoinAddress.swift // HDWalletKit // // Created by Pavlo Boiko on 1/8/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public enum AddressType { case pubkeyHash case scriptHash case wif } public protocol AddressProtocol { var coin: Coin { get } var type: AddressType { get } var data: Data { get } var base58: String { get } var cashaddr: String { get } } public typealias Address = AddressProtocol public enum AddressError: Error { case invalid case invalidScheme case invalidVersionByte } public struct LegacyAddress: Address { public let coin: Coin public let type: AddressType public let data: Data public let base58: Base58Check public let cashaddr: String public typealias Base58Check = String public init(_ base58: Base58Check, coin: Coin) throws { guard let raw = Base58.decode(base58) else { throw AddressError.invalid } let checksum = raw.suffix(4) let pubKeyHash = raw.dropLast(4) let checksumConfirm = pubKeyHash.doubleSHA256.prefix(4) guard checksum == checksumConfirm else { throw AddressError.invalid } self.coin = coin let type: AddressType let addressPrefix = pubKeyHash[0] switch addressPrefix { case coin.publicKeyHash: type = .pubkeyHash case coin.wifAddressPrefix: type = .wif case coin.scriptHash: type = .scriptHash default: throw AddressError.invalidVersionByte } self.type = type self.data = pubKeyHash.dropFirst() self.base58 = base58 // cashaddr switch type { case .pubkeyHash: let payload = Data([coin.publicKeyHash]) + self.data self.cashaddr = Bech32.encode(payload, prefix: coin.scheme) case .wif: let payload = Data([coin.wifAddressPrefix]) + self.data self.cashaddr = Bech32.encode(payload, prefix: coin.scheme) default: self.cashaddr = "" } } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Bitcoin/BitcoinTransactionSignatureSerializer.swift ================================================ // // BitcoinTransactionSignatureSerializer.swift // HDWalletKit // // Created by Pavlo Boiko on 2/5/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public struct BitcoinTransactionSignatureSerializer { var tx: Transaction var utxo: TransactionOutput var inputIndex: Int var hashType: SighashType // input should be modified before sign internal func modifiedInput(for i: Int) -> TransactionInput { let txin = tx.inputs[i] let sigScript: Data let sequence: UInt32 if i == inputIndex { let subScript = Script(data: utxo.lockingScript) try! subScript?.deleteOccurrences(of: .OP_CODESEPARATOR) sigScript = subScript?.data ?? Data() sequence = txin.sequence } else if hashType.isNone || hashType.isSingle { // If hashtype is NONE or SINGLE, blank out others' input sequence numbers to let others update transaction at will. sigScript = Data() sequence = 0 } else { sigScript = Data() sequence = txin.sequence } return TransactionInput(previousOutput: txin.previousOutput, signatureScript: sigScript, sequence: sequence) } public func serialize() -> Data { let inputsToSerialize: [TransactionInput] let outputsToSerialize: [TransactionOutput] // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized if hashType.isAnyoneCanPay { inputsToSerialize = [modifiedInput(for: inputIndex)] } else { inputsToSerialize = (0.. Data { if !hashType.isAnyoneCanPay { // If the ANYONECANPAY flag is not set, hashPrevouts is the double SHA256 of the serialization of all input outpoints let serializedPrevouts: Data = inputs.reduce(Data()) { $0 + $1.previousOutput.serialized() } return serializedPrevouts.doubleSHA256 } else { // if ANYONECANPAY then uint256 of 0x0000......0000. return zero } } internal func getSequenceHash(hashType: SighashType) -> Data { if !hashType.isAnyoneCanPay && !hashType.isSingle && !hashType.isNone { // If none of the ANYONECANPAY, SINGLE, NONE sighash type is set, hashSequence is the double SHA256 of the serialization of nSequence of all inputs let serializedSequence: Data = inputs.reduce(Data()) { $0 + $1.sequence } return serializedSequence.doubleSHA256 } else { // Otherwise, hashSequence is a uint256 of 0x0000......0000 return zero } } internal func getOutputsHash(index: Int, hashType: SighashType) -> Data { if !hashType.isSingle && !hashType.isNone { // If the sighash type is neither SINGLE nor NONE, hashOutputs is the double SHA256 of the serialization of all output amounts (8-byte little endian) paired up with their scriptPubKey (serialized as scripts inside CTxOuts) let serializedOutputs: Data = outputs.reduce(Data()) { $0 + $1.serialized() } return serializedOutputs.doubleSHA256 } else if hashType.isSingle && index < outputs.count { // If sighash type is SINGLE and the input index is smaller than the number of outputs, hashOutputs is the double SHA256 of the output amount with scriptPubKey of the same index as the input let serializedOutput = outputs[index].serialized() return serializedOutput.doubleSHA256 } else { // Otherwise, hashOutputs is a uint256 of 0x0000......0000. return zero } } internal func signatureHashLegacy(for utxo: TransactionOutput, inputIndex: Int, hashType: SighashType) -> Data { // If inputIndex is out of bounds, BitcoinABC is returning a 256-bit little-endian 0x01 instead of failing with error. guard inputIndex < inputs.count else { // tx.inputs[inputIndex] out of range return one } // Check for invalid use of SIGHASH_SINGLE guard !(hashType.isSingle && inputIndex < outputs.count) else { // tx.outputs[inputIndex] out of range return one } // Transaction is struct(value type), so it's ok to use self as an arg let txSigSerializer = BitcoinTransactionSignatureSerializer(tx: self, utxo: utxo, inputIndex: inputIndex, hashType: hashType) var data: Data = txSigSerializer.serialize() data += UInt32(hashType) let hash = data.doubleSHA256 return hash } public func signatureHash(for utxo: TransactionOutput, inputIndex: Int, hashType: SighashType) -> Data { // If hashType doesn't have a fork id, use legacy signature hash guard hashType.hasForkId else { return signatureHashLegacy(for: utxo, inputIndex: inputIndex, hashType: hashType) } // "txin" ≒ "utxo" // "txin" is an input of this tx // "utxo" is an output of the prev tx // Currently not handling "inputIndex is out of range error" because BitcoinABC implementation is not handling this. let txin = inputs[inputIndex] var data = Data() // 1. nVersion (4-byte) data += version // 2. hashPrevouts data += getPrevoutHash(hashType: hashType) // 3. hashSequence data += getSequenceHash(hashType: hashType) // 4. outpoint [of the input txin] data += txin.previousOutput.serialized() // 5. scriptCode [of the input txout] data += utxo.scriptCode() // 6. value [of the input txout] (8-byte) data += utxo.value // 7. nSequence [of the input txin] (4-byte) data += txin.sequence // 8. hashOutputs data += getOutputsHash(index: inputIndex, hashType: hashType) // 9. nLocktime (4-byte) data += lockTime // 10. Sighash types [This time input] (4-byte) data += UInt32(hashType) let hash = data.doubleSHA256 return hash } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/BitcoinCash/BitcoinCashAddress.swift ================================================ // // BitcoinCashAddress.swift // HDWalletKit // // Created by Pavlo Boiko on 5/1/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public struct BitcoinCashAddress: Address { public let coin: Coin public let type: AddressType public let data: Data public let base58: String public let cashaddr: String public init(_ cashaddr: String) throws { guard let decoded = Bech32.decode(cashaddr) else { throw AddressError.invalid } let raw = decoded.data self.cashaddr = cashaddr self.coin = .bitcoinCash let versionByte = raw[0] let hash = raw.dropFirst() guard hash.count == BitcoinCashVersionByte.getSize(from: versionByte) else { throw AddressError.invalidVersionByte } self.data = hash guard let typeBits = BitcoinCashVersionByte.TypeBits(rawValue: (versionByte & 0b01111000)) else { throw AddressError.invalidVersionByte } switch typeBits { case .pubkeyHash: type = .pubkeyHash base58 = publicKeyHashToAddress(Data([coin.publicKeyHash]) + data) case .scriptHash: type = .scriptHash base58 = publicKeyHashToAddress(Data([coin.scriptHash]) + data) } } } func publicKeyHashToAddress(_ hash: Data) -> String { let checksum = hash.doubleSHA256.prefix(4) let address = Base58.encode(hash + checksum) return address } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/BitcoinCash/BitcoinCashVersionByte.swift ================================================ // // BitcoinCashVersionByte.swift // HDWalletKit // // Created by Pavlo Boiko on 1/8/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public class BitcoinCashVersionByte { static let pubkeyHash160: UInt8 = PubkeyHash160().bytes static let scriptHash160: UInt8 = ScriptHash160().bytes var bytes: UInt8 { return type.rawValue + size.rawValue } public var type: TypeBits { return .pubkeyHash } public var size: SizeBits { return .size160 } public static func getSize(from versionByte: UInt8) -> Int { guard let sizeBits = SizeBits(rawValue: versionByte & 0x07) else { return 0 } switch sizeBits { case .size160: return 20 case .size192: return 24 case .size224: return 28 case .size256: return 32 case .size320: return 40 case .size384: return 48 case .size448: return 56 case .size512: return 64 } } // First 1 bit is zero // Next 4bits public enum TypeBits: UInt8 { case pubkeyHash = 0 case scriptHash = 8 } // The least 3bits public enum SizeBits: UInt8 { case size160 = 0 case size192 = 1 case size224 = 2 case size256 = 3 case size320 = 4 case size384 = 5 case size448 = 6 case size512 = 7 } } public class PubkeyHash160: BitcoinCashVersionByte { public override var size: SizeBits { return .size160 } public override var type: TypeBits { return .pubkeyHash } } public class ScriptHash160: BitcoinCashVersionByte { public override var size: SizeBits { return .size160 } public override var type: TypeBits { return .scriptHash } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Constants/SighashType.swift ================================================ // // SighashType.swift // HDWalletKit // // Created by Pavlo Boiko on 1/7/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation private let SIGHASH_ALL: UInt8 = 0x01 // 00000001 private let SIGHASH_NONE: UInt8 = 0x02 // 00000010 private let SIGHASH_SINGLE: UInt8 = 0x03 // 00000011 private let SIGHASH_FORK_ID: UInt8 = 0x40 // 01000000 private let SIGHASH_ANYONECANPAY: UInt8 = 0x80 // 10000000 private let SIGHASH_OUTPUT_MASK: UInt8 = 0x1f // 00011111 public struct SighashType { fileprivate let uint8: UInt8 init(_ uint8: UInt8) { self.uint8 = uint8 } private var outputType: UInt8 { return self.uint8 & SIGHASH_OUTPUT_MASK } public var isAll: Bool { return outputType == SIGHASH_ALL } public var isSingle: Bool { return outputType == SIGHASH_SINGLE } public var isNone: Bool { return outputType == SIGHASH_NONE } public var hasForkId: Bool { return (self.uint8 & SIGHASH_FORK_ID) != 0 } public var isAnyoneCanPay: Bool { return (self.uint8 & SIGHASH_ANYONECANPAY) != 0 } public struct BCH { public static let ALL: SighashType = SighashType(SIGHASH_FORK_ID + SIGHASH_ALL) // 01000001 public static let NONE: SighashType = SighashType(SIGHASH_FORK_ID + SIGHASH_NONE) // 01000010 public static let SINGLE: SighashType = SighashType(SIGHASH_FORK_ID + SIGHASH_SINGLE) // 01000011 public static let ALL_ANYONECANPAY: SighashType = SighashType(SIGHASH_FORK_ID + SIGHASH_ALL + SIGHASH_ANYONECANPAY) // 11000001 public static let NONE_ANYONECANPAY: SighashType = SighashType(SIGHASH_FORK_ID + SIGHASH_NONE + SIGHASH_ANYONECANPAY) // 11000010 public static let SINGLE_ANYONECANPAY: SighashType = SighashType(SIGHASH_FORK_ID + SIGHASH_SINGLE + SIGHASH_ANYONECANPAY) // 11000011 } public struct BTC { public static let ALL: SighashType = SighashType(SIGHASH_ALL) // 00000001 public static let NONE: SighashType = SighashType(SIGHASH_NONE) // 00000010 public static let SINGLE: SighashType = SighashType(SIGHASH_SINGLE) // 00000011 public static let ALL_ANYONECANPAY: SighashType = SighashType(SIGHASH_ALL + SIGHASH_ANYONECANPAY) // 10000001 public static let NONE_ANYONECANPAY: SighashType = SighashType(SIGHASH_NONE + SIGHASH_ANYONECANPAY) // 10000010 public static let SINGLE_ANYONECANPAY: SighashType = SighashType(SIGHASH_SINGLE + SIGHASH_ANYONECANPAY) // 10000011 } static func hashTypeForCoin(coin: Coin) -> SighashType { switch coin { case .bitcoinCash: return BCH.ALL default: return BTC.ALL } } } extension UInt8 { public init(_ hashType: SighashType) { self = hashType.uint8 } } extension UInt32 { public init(_ hashType: SighashType) { self = UInt32(UInt8(hashType)) } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Constants/UtilsAndLimits.swift ================================================ // // UtilsAndLimits.swift // HDWalletKit // // Created by Pavlo Boiko on 1/6/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation // P2SH BIP16 didn't become active until Apr 1 2012. All txs before this timestamp should not be verified with P2SH rule. let BTC_BIP16_TIMESTAMP: UInt32 = 1_333_238_400 // Scripts longer than 10000 bytes are invalid. let BTC_MAX_SCRIPT_SIZE: Int = 10_000 // Maximum number of bytes per "pushdata" operation let BTC_MAX_SCRIPT_ELEMENT_SIZE: Int = 520; // bytes // Number of public keys allowed for OP_CHECKMULTISIG let BTC_MAX_KEYS_FOR_CHECKMULTISIG: Int = 20 // Maximum number of operations allowed per script (excluding pushdata operations and OP_) // Multisig op additionally increases count by a number of pubkeys. let BTC_MAX_OPS_PER_SCRIPT: Int = 201 let BTC_LOCKTIME_THRESHOLD: UInt32 = 500_000_000 ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Default/UtxoSelector.swift ================================================ // // UtxoSelector.swift // HDWalletKit // // Created by Pavlo Boiko on 2/12/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public class UtxoSelector: UtxoSelectorInterface { public let feePerByte: UInt64 public let dustThreshhold: UInt64 public init(feePerByte: UInt64 = 1, dustThreshhold: UInt64 = 3 * 182) { self.feePerByte = feePerByte self.dustThreshhold = dustThreshhold } public func select(from utxos: [UnspentTransaction], targetValue: UInt64) throws -> (utxos: [UnspentTransaction], fee: UInt64) { // if target value is zero, fee is zero guard targetValue > 0 else { return ([], 0) } // definitions for the following caluculation let doubleTargetValue = targetValue * 2 var numOutputs = 2 // if allow multiple output, it will be changed. var numInputs = 2 var fee: UInt64 { return calculateFee(nIn: numInputs, nOut: numOutputs) } var targetWithFee: UInt64 { return targetValue + fee } var targetWithFeeAndDust: UInt64 { return targetWithFee + dustThreshhold } let sortedUtxos: [UnspentTransaction] = utxos.sorted(by: { $0.output.value < $1.output.value }) // total values of utxos should be greater than targetValue guard sortedUtxos.sum() >= targetValue && !sortedUtxos.isEmpty else { throw UtxoSelectError.insufficientFunds } // difference from 2x targetValue func distFrom2x(_ val: UInt64) -> UInt64 { if val > doubleTargetValue { return val - doubleTargetValue } else { return doubleTargetValue - val } } // 1. Find a combination of the fewest outputs that is // (1) bigger than what we need // (2) closer to 2x the amount, // (3) and does not produce dust change. txN:do { for numTx in (1...sortedUtxos.count) { numInputs = numTx let nOutputsSlices = sortedUtxos.eachSlices(numInputs) var nOutputsInRange = nOutputsSlices.filter { $0.sum() >= targetWithFeeAndDust } nOutputsInRange.sort { distFrom2x($0.sum()) < distFrom2x($1.sum()) } if let nOutputs = nOutputsInRange.first { return (nOutputs, fee) } } } // 2. If not, find a combination of outputs that may produce dust change. txDiscardDust:do { for numTx in (1...sortedUtxos.count) { numInputs = numTx let nOutputsSlices = sortedUtxos.eachSlices(numInputs) let nOutputsInRange = nOutputsSlices.filter { return $0.sum() >= targetWithFee } if let nOutputs = nOutputsInRange.first { return (nOutputs, fee) } } } throw UtxoSelectError.insufficientFunds } private func calculateFee(nIn: Int, nOut: Int = 2) -> UInt64 { var txsize: Int { return ((148 * nIn) + (34 * nOut) + 10) } return UInt64(txsize) * feePerByte } } enum UtxoSelectError: Error { case insufficientFunds case error(String) } private extension Array { // Slice Array // [0,1,2,3,4,5,6,7,8,9].eachSlices(3) // > // [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9]] func eachSlices(_ num: Int) -> [[Element]] { let slices = (0...count - num).map { self[$0..<$0 + num].map { $0 } } return slices } } internal extension Sequence where Element == UnspentTransaction { func sum() -> UInt64 { return reduce(UInt64()) { $0 + $1.output.value } } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Default/UtxoTransactionBuilder.swift ================================================ // // UtxoTransactionBuilder.swift // HDWalletKit // // Created by Pavlo Boiko on 2/17/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public struct UtxoTransactionBuilder: UtxoTransactionBuilderInterface { public init() {} public func build(destinations: [(address: Address, amount: UInt64)], utxos: [UnspentTransaction]) throws -> UnsignedTransaction { let outputs = try destinations.map { (address: Address, amount: UInt64) -> TransactionOutput in guard let lockingScript = Script(address: address)?.data else { throw TransactionBuildError.error("Invalid address type") } return TransactionOutput(value: amount, lockingScript: lockingScript) } let unsignedInputs = utxos.map { TransactionInput(previousOutput: $0.outpoint, signatureScript: $0.output.lockingScript, sequence: UInt32.max) } let tx = Transaction(version: 1, inputs: unsignedInputs, outputs: outputs, lockTime: 0) return UnsignedTransaction(tx: tx, utxos: utxos) } } enum TransactionBuildError: Error { case error(String) } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Default/UtxoTransactionSigner.swift ================================================ // // UtxoTransactionSigner.swift // HDWalletKit // // Created by Pavlo Boiko on 2/19/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public struct UtxoTransactionSigner: UtxoTransactionSignerInterface { public init() {} public func sign(_ unsignedTransaction: UnsignedTransaction, with key: PrivateKey) throws -> Transaction { // Define Transaction var signingInputs: [TransactionInput] var signingTransaction: Transaction { let tx: Transaction = unsignedTransaction.tx return Transaction(version: tx.version, inputs: signingInputs, outputs: tx.outputs, lockTime: tx.lockTime) } // Sign signingInputs = unsignedTransaction.tx.inputs let hashType = SighashType.hashTypeForCoin(coin: key.coin) for (i, utxo) in unsignedTransaction.utxos.enumerated() { // Sign transaction hash let sighash: Data = signingTransaction.signatureHash(for: utxo.output, inputIndex: i, hashType: hashType) let signature: Data = try ECDSA.sign(sighash, privateKey: key.raw) let txin = signingInputs[i] let pubkey = key.publicKey // Create Signature Script let sigWithHashType: Data = signature + UInt8(hashType) let unlockingScript: Script = try Script() .appendData(sigWithHashType) .appendData(pubkey.data) // Update TransactionInput signingInputs[i] = TransactionInput(previousOutput: txin.previousOutput, signatureScript: unlockingScript.data, sequence: txin.sequence) } return signingTransaction } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Model/TransactionInput.swift ================================================ // // BitcoinTransactionInput.swift // HDWalletKit // // Created by Pavlo Boiko on 1/7/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public struct TransactionInput { /// The previous output transaction reference, as an OutPoint structure public let previousOutput: TransactionOutPoint /// The length of the signature script public var scriptLength: VarInt { return VarInt(signatureScript.count) } /// Computational Script for confirming transaction authorization public let signatureScript: Data /// Transaction version as defined by the sender. Intended for "replacement" of transactions when information is updated before inclusion into a block. public let sequence: UInt32 public init(previousOutput: TransactionOutPoint, signatureScript: Data, sequence: UInt32) { self.previousOutput = previousOutput self.signatureScript = signatureScript self.sequence = sequence } public func isCoinbase() -> Bool { return previousOutput.hash == Data(count: 32) && previousOutput.index == 0xFFFF_FFFF } public func serialized() -> Data { var data = Data() data += previousOutput.serialized() data += scriptLength.serialized() data += signatureScript data += sequence return data } static func deserialize(_ byteStream: ByteStream) -> TransactionInput { let previousOutput = TransactionOutPoint.deserialize(byteStream) let scriptLength = byteStream.read(VarInt.self) let signatureScript = byteStream.read(Data.self, count: Int(scriptLength.underlyingValue)) let sequence = byteStream.read(UInt32.self) return TransactionInput(previousOutput: previousOutput, signatureScript: signatureScript, sequence: sequence) } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Model/UnsignedTransaction.swift ================================================ // // UnsignedTransaction.swift // HDWalletKit // // Created by Pavlo Boiko on 2/17/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public struct UnsignedTransaction { public let tx: Transaction public let utxos: [UnspentTransaction] public init(tx: Transaction, utxos: [UnspentTransaction]) { self.tx = tx self.utxos = utxos } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Model/UnspendTransaction/TransactionOutPoint.swift ================================================ // // BitcoinTransactionOutPoint.swift // HDWalletKit // // Created by Pavlo Boiko on 12/28/18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation import CryptoSwift public struct TransactionOutPoint { /// The hash of the referenced transaction. public let hash: Data /// The index of the specific output in the transaction. The first output is 0, etc. public let index: UInt32 public init(hash: Data, index: UInt32) { self.hash = hash self.index = index } public func serialized() -> Data { var data = Data() data += hash data += index return data } static func deserialize(_ byteStream: ByteStream) -> TransactionOutPoint { let hash = Data(byteStream.read(Data.self, count: 32)) let index = byteStream.read(UInt32.self) return TransactionOutPoint(hash: hash, index: index) } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Model/UnspendTransaction/TransactionOutput.swift ================================================ // // BitcoinTransactionOutput.swift // HDWalletKit // // Created by Pavlo Boiko on 12/28/18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public struct TransactionOutput { /// Transaction Value public let value: UInt64 /// Length of the pk_script public var scriptLength: VarInt { return VarInt(lockingScript.count) } /// Usually contains the public key as a Bitcoin script setting up conditions to claim this output public let lockingScript: Data public func scriptCode() -> Data { var data = Data() data += scriptLength.serialized() data += lockingScript return data } public init(value: UInt64, lockingScript: Data) { self.value = value self.lockingScript = lockingScript } public init() { self.init(value: 0, lockingScript: Data()) } public func serialized() -> Data { var data = Data() data += value data += scriptLength.serialized() data += lockingScript return data } static func deserialize(_ byteStream: ByteStream) -> TransactionOutput { let value = byteStream.read(UInt64.self) let scriptLength = byteStream.read(VarInt.self) let lockingScript = byteStream.read(Data.self, count: Int(scriptLength.underlyingValue)) return TransactionOutput(value: value, lockingScript: lockingScript) } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Model/UnspendTransaction/UnspendTransaction.swift ================================================ // // UnspendTransaction.swift // HDWalletKit // // Created by Pavlo Boiko on 12/28/18. // Copyright © 2018 Essentia. All rights reserved. // import Foundation public struct UnspentTransaction { public let output: TransactionOutput public let outpoint: TransactionOutPoint public init(output: TransactionOutput, outpoint: TransactionOutPoint) { self.output = output self.outpoint = outpoint } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Protocols/UtxoSelectorInterface.swift ================================================ // // UTXOSelector.swift // HDWalletKit // // Created by Pavlo Boiko on 2/19/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public protocol UtxoSelectorInterface { func select(from utxos: [UnspentTransaction], targetValue: UInt64) throws -> (utxos: [UnspentTransaction], fee: UInt64) } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Protocols/UtxoTransactionBuilderInterface.swift ================================================ // // UtxoTransactionBuilder.swift // HDWalletKit // // Created by Pavlo Boiko on 2/19/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public protocol UtxoTransactionBuilderInterface { func build(destinations: [(address: Address, amount: UInt64)], utxos: [UnspentTransaction]) throws -> UnsignedTransaction } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Protocols/UtxoTransactionSignerInterface.swift ================================================ // // UtxoTransactionSigner.swift // HDWalletKit // // Created by Pavlo Boiko on 2/19/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public protocol UtxoTransactionSignerInterface { func sign(_ unsignedTransaction: UnsignedTransaction, with key: PrivateKey) throws -> Transaction } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/Transaction.swift ================================================ // // BitcoinTransaction.swift // HDWalletKit // // Created by Pavlo Boiko on 1/8/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation /// tx describes a bitcoin transaction, in reply to getdata public struct Transaction { /// Transaction data format version (note, this is signed) public let version: UInt32 /// If present, always 0001, and indicates the presence of witness data // public let flag: UInt16 // If present, always 0001, and indicates the presence of witness data /// Number of Transaction inputs (never zero) public var txInCount: VarInt { return VarInt(inputs.count) } /// A list of 1 or more transaction inputs or sources for coins public let inputs: [TransactionInput] /// Number of Transaction outputs public var txOutCount: VarInt { return VarInt(outputs.count) } /// A list of 1 or more transaction outputs or destinations for coins public let outputs: [TransactionOutput] /// A list of witnesses, one for each input; omitted if flag is omitted above // public let witnesses: [TransactionWitness] // A list of witnesses, one for each input; omitted if flag is omitted above /// The block number or timestamp at which this transaction is unlocked: public let lockTime: UInt32 public var txHash: Data { return serialized().doubleSHA256 } public var txID: String { return Data(txHash.reversed()).hex } public init(version: UInt32, inputs: [TransactionInput], outputs: [TransactionOutput], lockTime: UInt32) { self.version = version self.inputs = inputs self.outputs = outputs self.lockTime = lockTime } public func serialized() -> Data { var data = Data() data += version data += txInCount.serialized() data += inputs.flatMap { $0.serialized() } data += txOutCount.serialized() data += outputs.flatMap { $0.serialized() } data += lockTime return data } public func isCoinbase() -> Bool { return inputs.count == 1 && inputs[0].isCoinbase() } public static func deserialize(_ data: Data) -> Transaction { let byteStream = ByteStream(data) return deserialize(byteStream) } static func deserialize(_ byteStream: ByteStream) -> Transaction { let version = byteStream.read(UInt32.self) let txInCount = byteStream.read(VarInt.self) var inputs = [TransactionInput]() for _ in 0.. String { let (utxosToSpend, fee) = try self.utxoSelector.select(from: utxos, targetValue: amount) let totalAmount: UInt64 = utxosToSpend.sum() let change: UInt64 = totalAmount - amount - fee let destinations: [(Address, UInt64)] = [(toAddress, amount), (privateKey.publicKey.utxoAddress, change)] let unsignedTx = try self.utxoTransactionBuilder.build(destinations: destinations, utxos: utxosToSpend) let signedTx = try self.utoxTransactionSigner.sign(unsignedTx, with: self.privateKey) return signedTx.serialized().hex } } ================================================ FILE: HDWalletKit/Wallet/UTXOBased/UtxoPrivateKeyType.swift ================================================ // // UtxoPrivateKeyType.swift // HDWalletKit // // Created by Pavlo Boiko on 4/17/19. // Copyright © 2019 Essentia. All rights reserved. // import Foundation public enum UtxoPrivateKeyType { case wifUncompressed case wifCompressed case hex private func regexForCoin(coin: Coin) -> String { switch coin { case .bitcoin: switch self { case .hex: return "^\\p{XDigit}+$" case .wifCompressed: return "[KL][1-9A-HJ-NP-Za-km-z]{51}" case .wifUncompressed: return "^5[HJK][0-9A-Za-z&&[^0OIl]]{49}" } case .litecoin: switch self { case .hex: return "^\\p{XDigit}+$" case .wifCompressed: return "[T][1-9A-HJ-NP-Za-km-z]{51}" case .wifUncompressed: return "^6[uv][1-9A-HJ-NP-Za-km-z]{49}" } case .ethereum: return "^\\p{XDigit}+$" case .bitcoinCash: switch self { case .hex: return "^\\p{XDigit}+$" case .wifCompressed: return "[KL][1-9A-HJ-NP-Za-km-z]{51}" case .wifUncompressed: return "^5[HJK][0-9A-Za-z&&[^0OIl]]{49}" } case .dash: switch self { case .hex: return "^\\p{XDigit}+$" case .wifCompressed: return "[X][1-9A-HJ-NP-Za-km-z]{51}" case .wifUncompressed: return "^7[rs][1-9A-HJ-NP-Za-km-z]{49}" } case .dogecoin: switch self { case .hex: return "^\\p{XDigit}+$" case .wifCompressed: return "[Q][1-9A-HJ-NP-Za-km-z]{51}" case .wifUncompressed: return "^6[LKJ][1-9A-HJ-NP-Za-km-z]{49}" } } } static func pkType(for pk: String, coin: Coin) -> UtxoPrivateKeyType? { let range = NSRange(location: 0, length: pk.utf16.count) return [UtxoPrivateKeyType.wifUncompressed, .wifCompressed, .hex].first(where: { let regexString = $0.regexForCoin(coin: coin) let regex = try? NSRegularExpression(pattern: regexString, options: []) return regex?.matches(in: pk, options: [], range: range).count == 1 }) } } ================================================ FILE: HDWalletKit/Wallet/Wallet.swift ================================================ // // Wallet.swift // WalletKit // // Created by yuzushioh on 2018/01/01. // Copyright © 2018 yuzushioh. All rights reserved. // import Foundation public final class Wallet { public let privateKey: PrivateKey public let coin: Coin public init(seed: Data, coin: Coin) { self.coin = coin privateKey = PrivateKey(seed: seed, coin: coin) } //MARK: - Public public func generateAddress(at index: UInt32) -> String { let derivedKey = bip44PrivateKey.derived(at: .notHardened(index)) return derivedKey.publicKey.address } public func generateAccount(at derivationPath: [DerivationNode]) -> Account { let privateKey = generatePrivateKey(at: derivationPath) return Account(privateKey: privateKey) } public func generateAccount(at index: UInt32 = 0) -> Account { let address = bip44PrivateKey.derived(at: .notHardened(index)) return Account(privateKey: address) } public func generateAccounts(count: UInt32) -> [Account] { var accounts:[Account] = [] for index in 0.. String { let signer = EIP155Signer(chainId: 1) let rawData = try signer.sign(rawTransaction, privateKey: privateKey) let hash = rawData.toHexString().addHexPrefix() return hash } //MARK: - Private //https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki private var bip44PrivateKey:PrivateKey { let bip44Purpose:UInt32 = 44 let purpose = privateKey.derived(at: .hardened(bip44Purpose)) let coinType = purpose.derived(at: .hardened(coin.coinType)) let account = coinType.derived(at: .hardened(0)) let receive = account.derived(at: .notHardened(0)) return receive } private func generatePrivateKey(at nodes:[DerivationNode]) -> PrivateKey { return privateKey(at: nodes) } private func privateKey(at nodes: [DerivationNode]) -> PrivateKey { var key: PrivateKey = privateKey for node in nodes { key = key.derived(at:node) } return key } } ================================================ FILE: HDWalletKit.podspec ================================================ Pod::Spec.new do |s| s.name = 'HDWalletKit' s.version = '0.3.6' s.summary = 'Hierarchical Deterministic(HD) wallet for cryptocurrencies in Swift' s.description = <<-DESC Simple Swift library for creating HD ([Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)) cryptocurrencies wallets and working with crypto Coins/ERC20 tokens. DESC s.homepage = 'https://github.com/essentiaone/HDWallet.git' s.license = { :type => 'MIT', :file => 'LICENSE.md' } s.author = { 'impl' => 'pavlo.bojkoo@gmail.com' } s.source = { :git => 'https://github.com/essentiaone/HDWallet.git', :tag => s.version.to_s } s.swift_version= '5' s.static_framework = true s.ios.deployment_target = '11.0' s.osx.deployment_target = '10.11' s.module_name = "HDWalletKit" s.source_files = 'HDWalletKit/**/*.{swift}' s.dependency 'secp256k1.swift', '~> 0.1.4' s.dependency 'CryptoSwift', '~> 1.0.0' end ================================================ FILE: HDWalletKit.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 51; objects = { /* Begin PBXBuildFile section */ 07F7F4339B91DA419CD2F41A /* Pods_HDWalletKit_HDWalletKit_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F9CF1786FD900D725E89FE5 /* Pods_HDWalletKit_HDWalletKit_Tests.framework */; }; 3401AEFA20F797CB006DEF49 /* EthereumAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3401AEF920F797CB006DEF49 /* EthereumAddress.swift */; }; 3401AF6E20F908AA006DEF49 /* SecpResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3401AF6D20F908AA006DEF49 /* SecpResult.swift */; }; 3411AEE72164278A00AB9476 /* Coin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3411AEE62164278A00AB9476 /* Coin.swift */; }; 3411AF0A21656F0700AB9476 /* PublicKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3411AF0921656F0700AB9476 /* PublicKey.swift */; }; 3411D0D82279FD3E0016D0C8 /* BitcoinCashAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3411D0D72279FD3E0016D0C8 /* BitcoinCashAddress.swift */; }; 342233BA227E7B7600C89968 /* ImportWalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 342233B9227E7B7600C89968 /* ImportWalletTests.swift */; }; 344167EC212CC100008B8A91 /* KeystoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344167EB212CC100008B8A91 /* KeystoreTests.swift */; }; 345639CA226F0CF000ED17DA /* RIPEMD160Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345639C9226F0CF000ED17DA /* RIPEMD160Tests.swift */; }; 345639CC226F42A500ED17DA /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 345639CB226F42A500ED17DA /* CryptoSwift.framework */; }; 345639D0226F58BD00ED17DA /* Secp256k1Tets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345639CF226F58BD00ED17DA /* Secp256k1Tets.swift */; }; 345B813222675002000E3460 /* UtxoPrivateKeyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345B813122675002000E3460 /* UtxoPrivateKeyType.swift */; }; 345B81342268A649000E3460 /* PrivateKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345B81332268A649000E3460 /* PrivateKeyTests.swift */; }; 34753F79216E76B70025E0F4 /* WeiEthterConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34753F78216E76B70025E0F4 /* WeiEthterConverter.swift */; }; 34753F7B216E78430025E0F4 /* ConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34753F7A216E78430025E0F4 /* ConverterTests.swift */; }; 348C10E721D68A2600295370 /* UnspendTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10E621D68A2600295370 /* UnspendTransaction.swift */; }; 348C10E921D68A3400295370 /* TransactionOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10E821D68A3400295370 /* TransactionOutput.swift */; }; 348C10EB21D68A4100295370 /* TransactionOutPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10EA21D68A4100295370 /* TransactionOutPoint.swift */; }; 348C115D21D68F2B00295370 /* OpCodeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10EE21D68F2B00295370 /* OpCodeProtocol.swift */; }; 348C115E21D68F2B00295370 /* ScriptChunk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10EF21D68F2B00295370 /* ScriptChunk.swift */; }; 348C115F21D68F2B00295370 /* ScriptFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F021D68F2B00295370 /* ScriptFactory.swift */; }; 348C116021D68F2B00295370 /* ScriptExecutionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F121D68F2B00295370 /* ScriptExecutionContext.swift */; }; 348C116121D68F2B00295370 /* ScriptChunkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F221D68F2B00295370 /* ScriptChunkHelper.swift */; }; 348C116221D68F2B00295370 /* OP_SHA1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F521D68F2B00295370 /* OP_SHA1.swift */; }; 348C116321D68F2B00295370 /* OP_HASH160.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F621D68F2B00295370 /* OP_HASH160.swift */; }; 348C116421D68F2B00295370 /* OP_SHA256.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F721D68F2B00295370 /* OP_SHA256.swift */; }; 348C116521D68F2B00295370 /* OP_CHECKMULTISIGVERIFY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F821D68F2B00295370 /* OP_CHECKMULTISIGVERIFY.swift */; }; 348C116621D68F2B00295370 /* OP_CHECKMULTISIG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10F921D68F2B00295370 /* OP_CHECKMULTISIG.swift */; }; 348C116721D68F2B00295370 /* OP_CHECKSIGVERIFY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10FA21D68F2B00295370 /* OP_CHECKSIGVERIFY.swift */; }; 348C116821D68F2B00295370 /* OP_RIPEMD160.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10FB21D68F2B00295370 /* OP_RIPEMD160.swift */; }; 348C116921D68F2B00295370 /* OP_CODESEPARATOR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10FC21D68F2B00295370 /* OP_CODESEPARATOR.swift */; }; 348C116A21D68F2B00295370 /* OP_CHECKSIG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10FD21D68F2B00295370 /* OP_CHECKSIG.swift */; }; 348C116B21D68F2B00295370 /* OP_HASH256.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10FE21D68F2B00295370 /* OP_HASH256.swift */; }; 348C116C21D68F2B00295370 /* OP_EXAMPLE.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C10FF21D68F2B00295370 /* OP_EXAMPLE.swift */; }; 348C116D21D68F2B00295370 /* OP_AND.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110121D68F2B00295370 /* OP_AND.swift */; }; 348C116E21D68F2B00295370 /* OP_INVERT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110221D68F2B00295370 /* OP_INVERT.swift */; }; 348C116F21D68F2B00295370 /* OP_EQUAL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110321D68F2B00295370 /* OP_EQUAL.swift */; }; 348C117021D68F2B00295370 /* OP_RESERVED2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110421D68F2B00295370 /* OP_RESERVED2.swift */; }; 348C117121D68F2B00295370 /* OP_EQUALVERIFY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110521D68F2B00295370 /* OP_EQUALVERIFY.swift */; }; 348C117221D68F2B00295370 /* OP_OR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110621D68F2B00295370 /* OP_OR.swift */; }; 348C117321D68F2B00295370 /* OP_XOR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110721D68F2B00295370 /* OP_XOR.swift */; }; 348C117421D68F2B00295370 /* OP_RESERVED1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110821D68F2B00295370 /* OP_RESERVED1.swift */; }; 348C117521D68F2B00295370 /* OP_PUBKEYHASH.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110A21D68F2B00295370 /* OP_PUBKEYHASH.swift */; }; 348C117621D68F2B00295370 /* OP_PUBKEY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110B21D68F2B00295370 /* OP_PUBKEY.swift */; }; 348C117721D68F2B00295370 /* OP_INVALIDOPCODE.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110C21D68F2B00295370 /* OP_INVALIDOPCODE.swift */; }; 348C117821D68F2B00295370 /* OP_BOOLAND.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110E21D68F2B00295370 /* OP_BOOLAND.swift */; }; 348C117921D68F2B00295370 /* OP_SUB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C110F21D68F2B00295370 /* OP_SUB.swift */; }; 348C117A21D68F2B00295370 /* OP_BOOLOR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111021D68F2B00295370 /* OP_BOOLOR.swift */; }; 348C117B21D68F2B00295370 /* OP_RSHIFT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111121D68F2B00295370 /* OP_RSHIFT.swift */; }; 348C117C21D68F2B00295370 /* OP_LSHIFT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111221D68F2B00295370 /* OP_LSHIFT.swift */; }; 348C117D21D68F2B00295370 /* OP_MAX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111321D68F2B00295370 /* OP_MAX.swift */; }; 348C117E21D68F2B00295370 /* OP_ADD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111421D68F2B00295370 /* OP_ADD.swift */; }; 348C117F21D68F2B00295370 /* OP_LESSTHAN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111521D68F2B00295370 /* OP_LESSTHAN.swift */; }; 348C118021D68F2B00295370 /* OP_NUMNOTEQUAL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111621D68F2B00295370 /* OP_NUMNOTEQUAL.swift */; }; 348C118121D68F2B00295370 /* OP_LESSTHANOREQUAL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111721D68F2B00295370 /* OP_LESSTHANOREQUAL.swift */; }; 348C118221D68F2B00295370 /* OP_MOD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111821D68F2B00295370 /* OP_MOD.swift */; }; 348C118321D68F2B00295370 /* OP_MUL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111921D68F2B00295370 /* OP_MUL.swift */; }; 348C118421D68F2B00295370 /* OP_DIV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111A21D68F2B00295370 /* OP_DIV.swift */; }; 348C118521D68F2B00295370 /* OP_GREATERTHANOREQUAL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111B21D68F2B00295370 /* OP_GREATERTHANOREQUAL.swift */; }; 348C118621D68F2B00295370 /* OP_NOT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111C21D68F2B00295370 /* OP_NOT.swift */; }; 348C118721D68F2B00295370 /* OP_GREATERTHAN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111D21D68F2B00295370 /* OP_GREATERTHAN.swift */; }; 348C118821D68F2B00295370 /* OP_1ADD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111E21D68F2B00295370 /* OP_1ADD.swift */; }; 348C118921D68F2B00295370 /* OP_WITHIN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C111F21D68F2B00295370 /* OP_WITHIN.swift */; }; 348C118A21D68F2B00295370 /* OP_NEGATE.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112021D68F2B00295370 /* OP_NEGATE.swift */; }; 348C118B21D68F2B00295370 /* OP_NUMEQUALVERIFY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112121D68F2B00295370 /* OP_NUMEQUALVERIFY.swift */; }; 348C118C21D68F2B00295370 /* OP_2MUL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112221D68F2B00295370 /* OP_2MUL.swift */; }; 348C118D21D68F2B00295370 /* OP_NUMEQUAL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112321D68F2B00295370 /* OP_NUMEQUAL.swift */; }; 348C118E21D68F2B00295370 /* OP_MIN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112421D68F2B00295370 /* OP_MIN.swift */; }; 348C118F21D68F2B00295370 /* OP_ABS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112521D68F2B00295370 /* OP_ABS.swift */; }; 348C119021D68F2B00295370 /* OP_2DIV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112621D68F2B00295370 /* OP_2DIV.swift */; }; 348C119121D68F2C00295370 /* OP_1SUB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112721D68F2B00295370 /* OP_1SUB.swift */; }; 348C119221D68F2C00295370 /* OP_0NOTEQUAL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112821D68F2B00295370 /* OP_0NOTEQUAL.swift */; }; 348C119321D68F2C00295370 /* OP_SIZE.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112A21D68F2B00295370 /* OP_SIZE.swift */; }; 348C119421D68F2C00295370 /* OP_BIN2NUM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112B21D68F2B00295370 /* OP_BIN2NUM.swift */; }; 348C119521D68F2C00295370 /* OP_CAT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112C21D68F2B00295370 /* OP_CAT.swift */; }; 348C119621D68F2C00295370 /* OP_NUM2BIN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112D21D68F2B00295370 /* OP_NUM2BIN.swift */; }; 348C119721D68F2C00295370 /* OP_SPLIT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C112E21D68F2B00295370 /* OP_SPLIT.swift */; }; 348C119821D68F2C00295370 /* OP_NOPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113021D68F2B00295370 /* OP_NOPN.swift */; }; 348C119921D68F2C00295370 /* OP_2SWAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113221D68F2B00295370 /* OP_2SWAP.swift */; }; 348C119A21D68F2C00295370 /* OP_TUCK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113321D68F2B00295370 /* OP_TUCK.swift */; }; 348C119B21D68F2C00295370 /* OP_ROLL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113421D68F2B00295370 /* OP_ROLL.swift */; }; 348C119C21D68F2C00295370 /* OP_SWAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113521D68F2B00295370 /* OP_SWAP.swift */; }; 348C119D21D68F2C00295370 /* OP_2DROP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113621D68F2B00295370 /* OP_2DROP.swift */; }; 348C119E21D68F2C00295370 /* OP_TOTALSTACK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113721D68F2B00295370 /* OP_TOTALSTACK.swift */; }; 348C119F21D68F2C00295370 /* OP_DROP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113821D68F2B00295370 /* OP_DROP.swift */; }; 348C11A021D68F2C00295370 /* OP_DEPTH.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113921D68F2B00295370 /* OP_DEPTH.swift */; }; 348C11A121D68F2C00295370 /* OP_FROMALTSTACK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113A21D68F2B00295370 /* OP_FROMALTSTACK.swift */; }; 348C11A221D68F2C00295370 /* OP_2DUP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113B21D68F2B00295370 /* OP_2DUP.swift */; }; 348C11A321D68F2C00295370 /* OP_3DUP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113C21D68F2B00295370 /* OP_3DUP.swift */; }; 348C11A421D68F2C00295370 /* OP_ROT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113D21D68F2B00295370 /* OP_ROT.swift */; }; 348C11A521D68F2C00295370 /* OP_PICK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113E21D68F2B00295370 /* OP_PICK.swift */; }; 348C11A621D68F2C00295370 /* OP_2OVER.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C113F21D68F2B00295370 /* OP_2OVER.swift */; }; 348C11A721D68F2C00295370 /* OP_NIP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114021D68F2B00295370 /* OP_NIP.swift */; }; 348C11A821D68F2C00295370 /* OP_IFDUP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114121D68F2B00295370 /* OP_IFDUP.swift */; }; 348C11A921D68F2C00295370 /* OP_DUP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114221D68F2B00295370 /* OP_DUP.swift */; }; 348C11AA21D68F2C00295370 /* OP_2ROT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114321D68F2B00295370 /* OP_2ROT.swift */; }; 348C11AB21D68F2C00295370 /* OP_OVER.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114421D68F2B00295370 /* OP_OVER.swift */; }; 348C11AC21D68F2C00295370 /* OP_CHECKLOCKTIMEVERIFY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114621D68F2B00295370 /* OP_CHECKLOCKTIMEVERIFY.swift */; }; 348C11AD21D68F2C00295370 /* OP_CHECKSEQUENCEVERIFY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114721D68F2B00295370 /* OP_CHECKSEQUENCEVERIFY.swift */; }; 348C11AE21D68F2C00295370 /* OP_RESERVED.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114921D68F2B00295370 /* OP_RESERVED.swift */; }; 348C11AF21D68F2C00295370 /* OP_1NEGATE.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114A21D68F2B00295370 /* OP_1NEGATE.swift */; }; 348C11B021D68F2C00295370 /* OP_0.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114B21D68F2B00295370 /* OP_0.swift */; }; 348C11B121D68F2C00295370 /* OP_N.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114C21D68F2B00295370 /* OP_N.swift */; }; 348C11B221D68F2C00295370 /* OP_PUSHDATA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114D21D68F2B00295370 /* OP_PUSHDATA.swift */; }; 348C11B321D68F2C00295370 /* OP_VER.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C114F21D68F2B00295370 /* OP_VER.swift */; }; 348C11B421D68F2C00295370 /* OP_NOTIF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115021D68F2B00295370 /* OP_NOTIF.swift */; }; 348C11B521D68F2C00295370 /* OP_RETURN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115121D68F2B00295370 /* OP_RETURN.swift */; }; 348C11B621D68F2C00295370 /* OP_VERIFY.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115221D68F2B00295370 /* OP_VERIFY.swift */; }; 348C11B721D68F2C00295370 /* OP_IF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115321D68F2B00295370 /* OP_IF.swift */; }; 348C11B821D68F2C00295370 /* OP_NOP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115421D68F2B00295370 /* OP_NOP.swift */; }; 348C11B921D68F2C00295370 /* OP_ELSE.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115521D68F2B00295370 /* OP_ELSE.swift */; }; 348C11BA21D68F2C00295370 /* OP_VERNOTIF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115621D68F2B00295370 /* OP_VERNOTIF.swift */; }; 348C11BB21D68F2C00295370 /* OP_VERIF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115721D68F2B00295370 /* OP_VERIF.swift */; }; 348C11BC21D68F2C00295370 /* OP_ENDIF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115821D68F2B00295370 /* OP_ENDIF.swift */; }; 348C11BD21D68F2C00295370 /* Opcode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115921D68F2B00295370 /* Opcode.swift */; }; 348C11BE21D68F2C00295370 /* OpCodeFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115A21D68F2B00295370 /* OpCodeFactory.swift */; }; 348C11BF21D68F2C00295370 /* Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115B21D68F2B00295370 /* Script.swift */; }; 348C11C021D68F2C00295370 /* ScriptMachine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C115C21D68F2B00295370 /* ScriptMachine.swift */; }; 348C11C921DFDB9400295370 /* Data+Script.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C11C821DFDB9400295370 /* Data+Script.swift */; }; 348C11CB21E1675B00295370 /* UtilsAndLimits.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348C11CA21E1675B00295370 /* UtilsAndLimits.swift */; }; 348FA3BC224A4C9D00DA3F1B /* UTXOSign.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348FA3BB224A4C9D00DA3F1B /* UTXOSign.swift */; }; 3492213320F64D9B00A59A6F /* BigInt+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492211C20F64D9B00A59A6F /* BigInt+Extension.swift */; }; 3492213420F64D9B00A59A6F /* SMP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492211D20F64D9B00A59A6F /* SMP.swift */; }; 3492213520F64D9B00A59A6F /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212020F64D9B00A59A6F /* Crypto.swift */; }; 3492213620F64D9B00A59A6F /* ECDSA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212120F64D9B00A59A6F /* ECDSA.swift */; }; 3492213720F64D9B00A59A6F /* RIPEMD160.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212320F64D9B00A59A6F /* RIPEMD160.swift */; }; 3492213820F64D9B00A59A6F /* DataConvertable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212420F64D9B00A59A6F /* DataConvertable.swift */; }; 3492213920F64D9B00A59A6F /* DerivationNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212520F64D9B00A59A6F /* DerivationNode.swift */; }; 3492213A20F64D9B00A59A6F /* Base58Encode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212720F64D9B00A59A6F /* Base58Encode.swift */; }; 3492213B20F64D9B00A59A6F /* EIP55.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212820F64D9B00A59A6F /* EIP55.swift */; }; 3492213C20F64D9B00A59A6F /* Mnemonic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212A20F64D9B00A59A6F /* Mnemonic.swift */; }; 3492213D20F64D9B00A59A6F /* WordList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212B20F64D9B00A59A6F /* WordList.swift */; }; 3492213E20F64D9B00A59A6F /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492212D20F64D9B00A59A6F /* Account.swift */; }; 3492214020F64D9B00A59A6F /* PrivateKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492213020F64D9B00A59A6F /* PrivateKey.swift */; }; 3492214220F64D9B00A59A6F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492213220F64D9B00A59A6F /* Wallet.swift */; }; 3492214C20F64E0300A59A6F /* libHDWalletKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 349220E520F64C6600A59A6F /* libHDWalletKit.a */; }; 3492215D20F6B4B600A59A6F /* EthereumRawTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492215720F6B4B400A59A6F /* EthereumRawTransaction.swift */; }; 3492216220F6B53300A59A6F /* Typealiaces.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492216120F6B53300A59A6F /* Typealiaces.swift */; }; 3492216520F6B79400A59A6F /* EIP155Signer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492216320F6B79300A59A6F /* EIP155Signer.swift */; }; 3492216620F6B79400A59A6F /* RLP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492216420F6B79400A59A6F /* RLP.swift */; }; 3492216B20F747EC00A59A6F /* EllipticCurveEncrypterSecp256k1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492216A20F747EC00A59A6F /* EllipticCurveEncrypterSecp256k1.swift */; }; 34A5322E215307DF00B95C66 /* SignTransactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A5322D215307DF00B95C66 /* SignTransactionTests.swift */; }; 34A532322158E66900B95C66 /* ERC20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A532312158E66900B95C66 /* ERC20.swift */; }; 34A532342158E96C00B95C66 /* ERC20Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A532332158E96C00B95C66 /* ERC20Tests.swift */; }; 34B7964A21296427000B1251 /* KeystoreV3Json.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7964921296427000B1251 /* KeystoreV3Json.swift */; }; 34B7964C212A881C000B1251 /* KeystoreInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7964B212A881C000B1251 /* KeystoreInterface.swift */; }; 34B7964E212A93A0000B1251 /* KeystoreV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7964D212A93A0000B1251 /* KeystoreV3.swift */; }; 34B79650212A95D5000B1251 /* Data+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7964F212A95D5000B1251 /* Data+Random.swift */; }; 34B7B84D20F7572900D2C34A /* HDWalletKitError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3492216820F7466800A59A6F /* HDWalletKitError.swift */; }; 34B7B84F20F75DBF00D2C34A /* MnemonicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7B84E20F75DBF00D2C34A /* MnemonicTests.swift */; }; 34B7B85120F75E4E00D2C34A /* CryptoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7B85020F75E4E00D2C34A /* CryptoTests.swift */; }; 34B7B85320F75E5B00D2C34A /* AddressGenerationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7B85220F75E5B00D2C34A /* AddressGenerationTests.swift */; }; 34B7B85720F7848D00D2C34A /* String+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B7B85620F7848D00D2C34A /* String+Hex.swift */; }; 34C9B1B621E2AE6700198EAF /* BigNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1B521E2AE6700198EAF /* BigNumber.swift */; }; 34C9B1B821E2B06300198EAF /* ByteStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1B721E2B06300198EAF /* ByteStream.swift */; }; 34C9B1BA21E2B09500198EAF /* VarInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1B921E2B09500198EAF /* VarInt.swift */; }; 34C9B1BC21E2B0D400198EAF /* VarString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1BB21E2B0D400198EAF /* VarString.swift */; }; 34C9B1BE21E2B38B00198EAF /* SighashType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1BD21E2B38B00198EAF /* SighashType.swift */; }; 34C9B1C021E2B3E700198EAF /* TransactionInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1BF21E2B3E700198EAF /* TransactionInput.swift */; }; 34C9B1C221E5065000198EAF /* BitcoinAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1C121E5065000198EAF /* BitcoinAddress.swift */; }; 34C9B1C821E5087900198EAF /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1C721E5087900198EAF /* Transaction.swift */; }; 34C9B1CA21E50A1700198EAF /* BitcoinCashVersionByte.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34C9B1C921E50A1700198EAF /* BitcoinCashVersionByte.swift */; }; 34D9CC442209BFAF00B3A625 /* Bech32.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CC432209BFAF00B3A625 /* Bech32.swift */; }; 34D9CC462209CD4300B3A625 /* Transaction+SignatureHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CC452209CD4300B3A625 /* Transaction+SignatureHash.swift */; }; 34D9CC482209CDB900B3A625 /* BitcoinTransactionSignatureSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CC472209CDB900B3A625 /* BitcoinTransactionSignatureSerializer.swift */; }; 34D9CC4A2212FE9D00B3A625 /* UtxoSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CC492212FE9D00B3A625 /* UtxoSelector.swift */; }; 34D9CF2C22199E6000B3A625 /* UtxoTransactionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CF2B22199E6000B3A625 /* UtxoTransactionBuilder.swift */; }; 34D9CF2E22199ED300B3A625 /* UnsignedTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CF2D22199ED300B3A625 /* UnsignedTransaction.swift */; }; 34D9CF30221C361D00B3A625 /* UTXOWallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CF2F221C361D00B3A625 /* UTXOWallet.swift */; }; 34D9CF35221C3A9900B3A625 /* UtxoSelectorInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CF34221C3A9900B3A625 /* UtxoSelectorInterface.swift */; }; 34D9CF37221C3AAF00B3A625 /* UtxoTransactionBuilderInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CF36221C3AAF00B3A625 /* UtxoTransactionBuilderInterface.swift */; }; 34D9CF39221C3AC100B3A625 /* UtxoTransactionSignerInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CF38221C3AC100B3A625 /* UtxoTransactionSignerInterface.swift */; }; 34D9CF48221C447D00B3A625 /* UtxoTransactionSigner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D9CF47221C447D00B3A625 /* UtxoTransactionSigner.swift */; }; 8602371595DB64FDBE46000C /* Pods_HDWalletKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A71916E6C32DA0D7349D72D7 /* Pods_HDWalletKit.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 3492214D20F64E0300A59A6F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 349220DD20F64C6600A59A6F /* Project object */; proxyType = 1; remoteGlobalIDString = 349220E420F64C6600A59A6F; remoteInfo = HDWalletKit; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 349220E320F64C6600A59A6F /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "include/$(PRODUCT_NAME)"; dstSubfolderSpec = 16; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 24463252CD56603F58800D8F /* Pods-HDWalletKit-HDWalletKit_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HDWalletKit-HDWalletKit_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HDWalletKit-HDWalletKit_Tests/Pods-HDWalletKit-HDWalletKit_Tests.debug.xcconfig"; sourceTree = ""; }; 29695349E80AB7F880E24B02 /* Pods-HDWalletKit_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HDWalletKit_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-HDWalletKit_Tests/Pods-HDWalletKit_Tests.release.xcconfig"; sourceTree = ""; }; 3401AEF920F797CB006DEF49 /* EthereumAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumAddress.swift; sourceTree = ""; }; 3401AF6D20F908AA006DEF49 /* SecpResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecpResult.swift; sourceTree = ""; }; 3411AEE62164278A00AB9476 /* Coin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coin.swift; sourceTree = ""; }; 3411AF0921656F0700AB9476 /* PublicKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicKey.swift; sourceTree = ""; }; 3411D0D72279FD3E0016D0C8 /* BitcoinCashAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinCashAddress.swift; sourceTree = ""; }; 342233B9227E7B7600C89968 /* ImportWalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportWalletTests.swift; sourceTree = ""; }; 344167EB212CC100008B8A91 /* KeystoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeystoreTests.swift; sourceTree = ""; }; 345639C9226F0CF000ED17DA /* RIPEMD160Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RIPEMD160Tests.swift; sourceTree = ""; }; 345639CB226F42A500ED17DA /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 345639CD226F42BC00ED17DA /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 345639CF226F58BD00ED17DA /* Secp256k1Tets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secp256k1Tets.swift; sourceTree = ""; }; 345B813122675002000E3460 /* UtxoPrivateKeyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtxoPrivateKeyType.swift; sourceTree = ""; }; 345B81332268A649000E3460 /* PrivateKeyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateKeyTests.swift; sourceTree = ""; }; 34753F78216E76B70025E0F4 /* WeiEthterConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeiEthterConverter.swift; sourceTree = ""; }; 34753F7A216E78430025E0F4 /* ConverterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConverterTests.swift; sourceTree = ""; }; 348C10E621D68A2600295370 /* UnspendTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnspendTransaction.swift; sourceTree = ""; }; 348C10E821D68A3400295370 /* TransactionOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionOutput.swift; sourceTree = ""; }; 348C10EA21D68A4100295370 /* TransactionOutPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionOutPoint.swift; sourceTree = ""; }; 348C10EE21D68F2B00295370 /* OpCodeProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpCodeProtocol.swift; sourceTree = ""; }; 348C10EF21D68F2B00295370 /* ScriptChunk.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScriptChunk.swift; sourceTree = ""; }; 348C10F021D68F2B00295370 /* ScriptFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScriptFactory.swift; sourceTree = ""; }; 348C10F121D68F2B00295370 /* ScriptExecutionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScriptExecutionContext.swift; sourceTree = ""; }; 348C10F221D68F2B00295370 /* ScriptChunkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScriptChunkHelper.swift; sourceTree = ""; }; 348C10F521D68F2B00295370 /* OP_SHA1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_SHA1.swift; sourceTree = ""; }; 348C10F621D68F2B00295370 /* OP_HASH160.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_HASH160.swift; sourceTree = ""; }; 348C10F721D68F2B00295370 /* OP_SHA256.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_SHA256.swift; sourceTree = ""; }; 348C10F821D68F2B00295370 /* OP_CHECKMULTISIGVERIFY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CHECKMULTISIGVERIFY.swift; sourceTree = ""; }; 348C10F921D68F2B00295370 /* OP_CHECKMULTISIG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CHECKMULTISIG.swift; sourceTree = ""; }; 348C10FA21D68F2B00295370 /* OP_CHECKSIGVERIFY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CHECKSIGVERIFY.swift; sourceTree = ""; }; 348C10FB21D68F2B00295370 /* OP_RIPEMD160.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_RIPEMD160.swift; sourceTree = ""; }; 348C10FC21D68F2B00295370 /* OP_CODESEPARATOR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CODESEPARATOR.swift; sourceTree = ""; }; 348C10FD21D68F2B00295370 /* OP_CHECKSIG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CHECKSIG.swift; sourceTree = ""; }; 348C10FE21D68F2B00295370 /* OP_HASH256.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_HASH256.swift; sourceTree = ""; }; 348C10FF21D68F2B00295370 /* OP_EXAMPLE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_EXAMPLE.swift; sourceTree = ""; }; 348C110121D68F2B00295370 /* OP_AND.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_AND.swift; sourceTree = ""; }; 348C110221D68F2B00295370 /* OP_INVERT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_INVERT.swift; sourceTree = ""; }; 348C110321D68F2B00295370 /* OP_EQUAL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_EQUAL.swift; sourceTree = ""; }; 348C110421D68F2B00295370 /* OP_RESERVED2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_RESERVED2.swift; sourceTree = ""; }; 348C110521D68F2B00295370 /* OP_EQUALVERIFY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_EQUALVERIFY.swift; sourceTree = ""; }; 348C110621D68F2B00295370 /* OP_OR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_OR.swift; sourceTree = ""; }; 348C110721D68F2B00295370 /* OP_XOR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_XOR.swift; sourceTree = ""; }; 348C110821D68F2B00295370 /* OP_RESERVED1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_RESERVED1.swift; sourceTree = ""; }; 348C110A21D68F2B00295370 /* OP_PUBKEYHASH.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_PUBKEYHASH.swift; sourceTree = ""; }; 348C110B21D68F2B00295370 /* OP_PUBKEY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_PUBKEY.swift; sourceTree = ""; }; 348C110C21D68F2B00295370 /* OP_INVALIDOPCODE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_INVALIDOPCODE.swift; sourceTree = ""; }; 348C110E21D68F2B00295370 /* OP_BOOLAND.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_BOOLAND.swift; sourceTree = ""; }; 348C110F21D68F2B00295370 /* OP_SUB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_SUB.swift; sourceTree = ""; }; 348C111021D68F2B00295370 /* OP_BOOLOR.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_BOOLOR.swift; sourceTree = ""; }; 348C111121D68F2B00295370 /* OP_RSHIFT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_RSHIFT.swift; sourceTree = ""; }; 348C111221D68F2B00295370 /* OP_LSHIFT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_LSHIFT.swift; sourceTree = ""; }; 348C111321D68F2B00295370 /* OP_MAX.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_MAX.swift; sourceTree = ""; }; 348C111421D68F2B00295370 /* OP_ADD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_ADD.swift; sourceTree = ""; }; 348C111521D68F2B00295370 /* OP_LESSTHAN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_LESSTHAN.swift; sourceTree = ""; }; 348C111621D68F2B00295370 /* OP_NUMNOTEQUAL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NUMNOTEQUAL.swift; sourceTree = ""; }; 348C111721D68F2B00295370 /* OP_LESSTHANOREQUAL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_LESSTHANOREQUAL.swift; sourceTree = ""; }; 348C111821D68F2B00295370 /* OP_MOD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_MOD.swift; sourceTree = ""; }; 348C111921D68F2B00295370 /* OP_MUL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_MUL.swift; sourceTree = ""; }; 348C111A21D68F2B00295370 /* OP_DIV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_DIV.swift; sourceTree = ""; }; 348C111B21D68F2B00295370 /* OP_GREATERTHANOREQUAL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_GREATERTHANOREQUAL.swift; sourceTree = ""; }; 348C111C21D68F2B00295370 /* OP_NOT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NOT.swift; sourceTree = ""; }; 348C111D21D68F2B00295370 /* OP_GREATERTHAN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_GREATERTHAN.swift; sourceTree = ""; }; 348C111E21D68F2B00295370 /* OP_1ADD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_1ADD.swift; sourceTree = ""; }; 348C111F21D68F2B00295370 /* OP_WITHIN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_WITHIN.swift; sourceTree = ""; }; 348C112021D68F2B00295370 /* OP_NEGATE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NEGATE.swift; sourceTree = ""; }; 348C112121D68F2B00295370 /* OP_NUMEQUALVERIFY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NUMEQUALVERIFY.swift; sourceTree = ""; }; 348C112221D68F2B00295370 /* OP_2MUL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_2MUL.swift; sourceTree = ""; }; 348C112321D68F2B00295370 /* OP_NUMEQUAL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NUMEQUAL.swift; sourceTree = ""; }; 348C112421D68F2B00295370 /* OP_MIN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_MIN.swift; sourceTree = ""; }; 348C112521D68F2B00295370 /* OP_ABS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_ABS.swift; sourceTree = ""; }; 348C112621D68F2B00295370 /* OP_2DIV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_2DIV.swift; sourceTree = ""; }; 348C112721D68F2B00295370 /* OP_1SUB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_1SUB.swift; sourceTree = ""; }; 348C112821D68F2B00295370 /* OP_0NOTEQUAL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_0NOTEQUAL.swift; sourceTree = ""; }; 348C112A21D68F2B00295370 /* OP_SIZE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_SIZE.swift; sourceTree = ""; }; 348C112B21D68F2B00295370 /* OP_BIN2NUM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_BIN2NUM.swift; sourceTree = ""; }; 348C112C21D68F2B00295370 /* OP_CAT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CAT.swift; sourceTree = ""; }; 348C112D21D68F2B00295370 /* OP_NUM2BIN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NUM2BIN.swift; sourceTree = ""; }; 348C112E21D68F2B00295370 /* OP_SPLIT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_SPLIT.swift; sourceTree = ""; }; 348C113021D68F2B00295370 /* OP_NOPN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NOPN.swift; sourceTree = ""; }; 348C113221D68F2B00295370 /* OP_2SWAP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_2SWAP.swift; sourceTree = ""; }; 348C113321D68F2B00295370 /* OP_TUCK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_TUCK.swift; sourceTree = ""; }; 348C113421D68F2B00295370 /* OP_ROLL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_ROLL.swift; sourceTree = ""; }; 348C113521D68F2B00295370 /* OP_SWAP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_SWAP.swift; sourceTree = ""; }; 348C113621D68F2B00295370 /* OP_2DROP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_2DROP.swift; sourceTree = ""; }; 348C113721D68F2B00295370 /* OP_TOTALSTACK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_TOTALSTACK.swift; sourceTree = ""; }; 348C113821D68F2B00295370 /* OP_DROP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_DROP.swift; sourceTree = ""; }; 348C113921D68F2B00295370 /* OP_DEPTH.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_DEPTH.swift; sourceTree = ""; }; 348C113A21D68F2B00295370 /* OP_FROMALTSTACK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_FROMALTSTACK.swift; sourceTree = ""; }; 348C113B21D68F2B00295370 /* OP_2DUP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_2DUP.swift; sourceTree = ""; }; 348C113C21D68F2B00295370 /* OP_3DUP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_3DUP.swift; sourceTree = ""; }; 348C113D21D68F2B00295370 /* OP_ROT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_ROT.swift; sourceTree = ""; }; 348C113E21D68F2B00295370 /* OP_PICK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_PICK.swift; sourceTree = ""; }; 348C113F21D68F2B00295370 /* OP_2OVER.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_2OVER.swift; sourceTree = ""; }; 348C114021D68F2B00295370 /* OP_NIP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NIP.swift; sourceTree = ""; }; 348C114121D68F2B00295370 /* OP_IFDUP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_IFDUP.swift; sourceTree = ""; }; 348C114221D68F2B00295370 /* OP_DUP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_DUP.swift; sourceTree = ""; }; 348C114321D68F2B00295370 /* OP_2ROT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_2ROT.swift; sourceTree = ""; }; 348C114421D68F2B00295370 /* OP_OVER.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_OVER.swift; sourceTree = ""; }; 348C114621D68F2B00295370 /* OP_CHECKLOCKTIMEVERIFY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CHECKLOCKTIMEVERIFY.swift; sourceTree = ""; }; 348C114721D68F2B00295370 /* OP_CHECKSEQUENCEVERIFY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_CHECKSEQUENCEVERIFY.swift; sourceTree = ""; }; 348C114921D68F2B00295370 /* OP_RESERVED.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_RESERVED.swift; sourceTree = ""; }; 348C114A21D68F2B00295370 /* OP_1NEGATE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_1NEGATE.swift; sourceTree = ""; }; 348C114B21D68F2B00295370 /* OP_0.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_0.swift; sourceTree = ""; }; 348C114C21D68F2B00295370 /* OP_N.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_N.swift; sourceTree = ""; }; 348C114D21D68F2B00295370 /* OP_PUSHDATA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_PUSHDATA.swift; sourceTree = ""; }; 348C114F21D68F2B00295370 /* OP_VER.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_VER.swift; sourceTree = ""; }; 348C115021D68F2B00295370 /* OP_NOTIF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NOTIF.swift; sourceTree = ""; }; 348C115121D68F2B00295370 /* OP_RETURN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_RETURN.swift; sourceTree = ""; }; 348C115221D68F2B00295370 /* OP_VERIFY.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_VERIFY.swift; sourceTree = ""; }; 348C115321D68F2B00295370 /* OP_IF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_IF.swift; sourceTree = ""; }; 348C115421D68F2B00295370 /* OP_NOP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_NOP.swift; sourceTree = ""; }; 348C115521D68F2B00295370 /* OP_ELSE.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_ELSE.swift; sourceTree = ""; }; 348C115621D68F2B00295370 /* OP_VERNOTIF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_VERNOTIF.swift; sourceTree = ""; }; 348C115721D68F2B00295370 /* OP_VERIF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_VERIF.swift; sourceTree = ""; }; 348C115821D68F2B00295370 /* OP_ENDIF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OP_ENDIF.swift; sourceTree = ""; }; 348C115921D68F2B00295370 /* Opcode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Opcode.swift; sourceTree = ""; }; 348C115A21D68F2B00295370 /* OpCodeFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpCodeFactory.swift; sourceTree = ""; }; 348C115B21D68F2B00295370 /* Script.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Script.swift; sourceTree = ""; }; 348C115C21D68F2B00295370 /* ScriptMachine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScriptMachine.swift; sourceTree = ""; }; 348C11C821DFDB9400295370 /* Data+Script.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Script.swift"; sourceTree = ""; }; 348C11CA21E1675B00295370 /* UtilsAndLimits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtilsAndLimits.swift; sourceTree = ""; }; 348FA3BB224A4C9D00DA3F1B /* UTXOSign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTXOSign.swift; sourceTree = ""; }; 349220E520F64C6600A59A6F /* libHDWalletKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHDWalletKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; 3492211C20F64D9B00A59A6F /* BigInt+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BigInt+Extension.swift"; sourceTree = ""; }; 3492211D20F64D9B00A59A6F /* SMP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMP.swift; sourceTree = ""; }; 3492212020F64D9B00A59A6F /* Crypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = ""; }; 3492212120F64D9B00A59A6F /* ECDSA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ECDSA.swift; sourceTree = ""; }; 3492212320F64D9B00A59A6F /* RIPEMD160.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RIPEMD160.swift; sourceTree = ""; }; 3492212420F64D9B00A59A6F /* DataConvertable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataConvertable.swift; sourceTree = ""; }; 3492212520F64D9B00A59A6F /* DerivationNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DerivationNode.swift; sourceTree = ""; }; 3492212720F64D9B00A59A6F /* Base58Encode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Base58Encode.swift; sourceTree = ""; }; 3492212820F64D9B00A59A6F /* EIP55.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP55.swift; sourceTree = ""; }; 3492212A20F64D9B00A59A6F /* Mnemonic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mnemonic.swift; sourceTree = ""; }; 3492212B20F64D9B00A59A6F /* WordList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WordList.swift; sourceTree = ""; }; 3492212D20F64D9B00A59A6F /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; 3492213020F64D9B00A59A6F /* PrivateKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateKey.swift; sourceTree = ""; }; 3492213220F64D9B00A59A6F /* Wallet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = ""; }; 3492214720F64E0300A59A6F /* HDWalletKit_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HDWalletKit_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3492214B20F64E0300A59A6F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3492215720F6B4B400A59A6F /* EthereumRawTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EthereumRawTransaction.swift; sourceTree = ""; }; 3492216120F6B53300A59A6F /* Typealiaces.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typealiaces.swift; sourceTree = ""; }; 3492216320F6B79300A59A6F /* EIP155Signer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP155Signer.swift; sourceTree = ""; }; 3492216420F6B79400A59A6F /* RLP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RLP.swift; sourceTree = ""; }; 3492216820F7466800A59A6F /* HDWalletKitError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HDWalletKitError.swift; sourceTree = ""; }; 3492216A20F747EC00A59A6F /* EllipticCurveEncrypterSecp256k1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EllipticCurveEncrypterSecp256k1.swift; sourceTree = ""; }; 34A5322D215307DF00B95C66 /* SignTransactionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignTransactionTests.swift; sourceTree = ""; }; 34A532312158E66900B95C66 /* ERC20.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ERC20.swift; sourceTree = ""; }; 34A532332158E96C00B95C66 /* ERC20Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ERC20Tests.swift; sourceTree = ""; }; 34B7964921296427000B1251 /* KeystoreV3Json.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeystoreV3Json.swift; sourceTree = ""; }; 34B7964B212A881C000B1251 /* KeystoreInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeystoreInterface.swift; sourceTree = ""; }; 34B7964D212A93A0000B1251 /* KeystoreV3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeystoreV3.swift; sourceTree = ""; }; 34B7964F212A95D5000B1251 /* Data+Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Random.swift"; sourceTree = ""; }; 34B7B84E20F75DBF00D2C34A /* MnemonicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MnemonicTests.swift; sourceTree = ""; }; 34B7B85020F75E4E00D2C34A /* CryptoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptoTests.swift; sourceTree = ""; }; 34B7B85220F75E5B00D2C34A /* AddressGenerationTests.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = AddressGenerationTests.swift; sourceTree = ""; }; 34B7B85620F7848D00D2C34A /* String+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Hex.swift"; sourceTree = ""; }; 34C9B1B521E2AE6700198EAF /* BigNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BigNumber.swift; sourceTree = ""; }; 34C9B1B721E2B06300198EAF /* ByteStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ByteStream.swift; sourceTree = ""; }; 34C9B1B921E2B09500198EAF /* VarInt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VarInt.swift; sourceTree = ""; }; 34C9B1BB21E2B0D400198EAF /* VarString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VarString.swift; sourceTree = ""; }; 34C9B1BD21E2B38B00198EAF /* SighashType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SighashType.swift; sourceTree = ""; }; 34C9B1BF21E2B3E700198EAF /* TransactionInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionInput.swift; sourceTree = ""; }; 34C9B1C121E5065000198EAF /* BitcoinAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinAddress.swift; sourceTree = ""; }; 34C9B1C721E5087900198EAF /* Transaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transaction.swift; sourceTree = ""; }; 34C9B1C921E50A1700198EAF /* BitcoinCashVersionByte.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinCashVersionByte.swift; sourceTree = ""; }; 34D9CC432209BFAF00B3A625 /* Bech32.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32.swift; sourceTree = ""; }; 34D9CC452209CD4300B3A625 /* Transaction+SignatureHash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Transaction+SignatureHash.swift"; sourceTree = ""; }; 34D9CC472209CDB900B3A625 /* BitcoinTransactionSignatureSerializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinTransactionSignatureSerializer.swift; sourceTree = ""; }; 34D9CC492212FE9D00B3A625 /* UtxoSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtxoSelector.swift; sourceTree = ""; }; 34D9CF2B22199E6000B3A625 /* UtxoTransactionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtxoTransactionBuilder.swift; sourceTree = ""; }; 34D9CF2D22199ED300B3A625 /* UnsignedTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsignedTransaction.swift; sourceTree = ""; }; 34D9CF2F221C361D00B3A625 /* UTXOWallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTXOWallet.swift; sourceTree = ""; }; 34D9CF34221C3A9900B3A625 /* UtxoSelectorInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtxoSelectorInterface.swift; sourceTree = ""; }; 34D9CF36221C3AAF00B3A625 /* UtxoTransactionBuilderInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtxoTransactionBuilderInterface.swift; sourceTree = ""; }; 34D9CF38221C3AC100B3A625 /* UtxoTransactionSignerInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtxoTransactionSignerInterface.swift; sourceTree = ""; }; 34D9CF47221C447D00B3A625 /* UtxoTransactionSigner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UtxoTransactionSigner.swift; sourceTree = ""; }; 6F9CF1786FD900D725E89FE5 /* Pods_HDWalletKit_HDWalletKit_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HDWalletKit_HDWalletKit_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 96ADBA88328A4BE2159563A5 /* Pods-HDWalletKit_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HDWalletKit_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HDWalletKit_Tests/Pods-HDWalletKit_Tests.debug.xcconfig"; sourceTree = ""; }; A241CE5210CEC9DFFCA47EA2 /* Pods-HDWalletKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HDWalletKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-HDWalletKit/Pods-HDWalletKit.release.xcconfig"; sourceTree = ""; }; A71916E6C32DA0D7349D72D7 /* Pods_HDWalletKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HDWalletKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BF520BDF5160D0B847AED112 /* Pods-HDWalletKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HDWalletKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HDWalletKit/Pods-HDWalletKit.debug.xcconfig"; sourceTree = ""; }; D4748DCAB4A042EBDF88023E /* Pods_HDWalletKit_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HDWalletKit_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FE9481BAD6A096D7EC0A2E49 /* Pods-HDWalletKit-HDWalletKit_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HDWalletKit-HDWalletKit_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-HDWalletKit-HDWalletKit_Tests/Pods-HDWalletKit-HDWalletKit_Tests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 349220E220F64C6600A59A6F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8602371595DB64FDBE46000C /* Pods_HDWalletKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 3492214420F64E0300A59A6F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 345639CC226F42A500ED17DA /* CryptoSwift.framework in Frameworks */, 3492214C20F64E0300A59A6F /* libHDWalletKit.a in Frameworks */, 07F7F4339B91DA419CD2F41A /* Pods_HDWalletKit_HDWalletKit_Tests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 3437FD9B227846E5000B1527 /* BitcoinCash */ = { isa = PBXGroup; children = ( 34C9B1C921E50A1700198EAF /* BitcoinCashVersionByte.swift */, 3411D0D72279FD3E0016D0C8 /* BitcoinCashAddress.swift */, ); path = BitcoinCash; sourceTree = ""; }; 34753F77216E76720025E0F4 /* Converter */ = { isa = PBXGroup; children = ( 34753F78216E76B70025E0F4 /* WeiEthterConverter.swift */, ); path = Converter; sourceTree = ""; }; 348C10E121D642CB00295370 /* Bitcoin */ = { isa = PBXGroup; children = ( 34C9B1C121E5065000198EAF /* BitcoinAddress.swift */, 34D9CC452209CD4300B3A625 /* Transaction+SignatureHash.swift */, 34D9CC472209CDB900B3A625 /* BitcoinTransactionSignatureSerializer.swift */, ); path = Bitcoin; sourceTree = ""; }; 348C10ED21D68F2B00295370 /* BitcoinScript */ = { isa = PBXGroup; children = ( 348C10EE21D68F2B00295370 /* OpCodeProtocol.swift */, 348C10EF21D68F2B00295370 /* ScriptChunk.swift */, 348C10F021D68F2B00295370 /* ScriptFactory.swift */, 348C10F121D68F2B00295370 /* ScriptExecutionContext.swift */, 348C10F221D68F2B00295370 /* ScriptChunkHelper.swift */, 348C10F321D68F2B00295370 /* OP_CODE */, 348C115921D68F2B00295370 /* Opcode.swift */, 348C115A21D68F2B00295370 /* OpCodeFactory.swift */, 348C115B21D68F2B00295370 /* Script.swift */, 348C115C21D68F2B00295370 /* ScriptMachine.swift */, ); path = BitcoinScript; sourceTree = ""; }; 348C10F321D68F2B00295370 /* OP_CODE */ = { isa = PBXGroup; children = ( 348C10F421D68F2B00295370 /* Crypto */, 348C10FF21D68F2B00295370 /* OP_EXAMPLE.swift */, 348C110021D68F2B00295370 /* Bitwise Logic */, 348C110921D68F2B00295370 /* Pseudo Words */, 348C110D21D68F2B00295370 /* Arithmetic */, 348C112921D68F2B00295370 /* Splice */, 348C112F21D68F2B00295370 /* Reserved Words */, 348C113121D68F2B00295370 /* Stack */, 348C114521D68F2B00295370 /* Lock Time */, 348C114821D68F2B00295370 /* Push Data */, 348C114E21D68F2B00295370 /* Flow Control */, ); path = OP_CODE; sourceTree = ""; }; 348C10F421D68F2B00295370 /* Crypto */ = { isa = PBXGroup; children = ( 348C10F521D68F2B00295370 /* OP_SHA1.swift */, 348C10F621D68F2B00295370 /* OP_HASH160.swift */, 348C10F721D68F2B00295370 /* OP_SHA256.swift */, 348C10F821D68F2B00295370 /* OP_CHECKMULTISIGVERIFY.swift */, 348C10F921D68F2B00295370 /* OP_CHECKMULTISIG.swift */, 348C10FA21D68F2B00295370 /* OP_CHECKSIGVERIFY.swift */, 348C10FB21D68F2B00295370 /* OP_RIPEMD160.swift */, 348C10FC21D68F2B00295370 /* OP_CODESEPARATOR.swift */, 348C10FD21D68F2B00295370 /* OP_CHECKSIG.swift */, 348C10FE21D68F2B00295370 /* OP_HASH256.swift */, ); path = Crypto; sourceTree = ""; }; 348C110021D68F2B00295370 /* Bitwise Logic */ = { isa = PBXGroup; children = ( 348C110121D68F2B00295370 /* OP_AND.swift */, 348C110221D68F2B00295370 /* OP_INVERT.swift */, 348C110321D68F2B00295370 /* OP_EQUAL.swift */, 348C110421D68F2B00295370 /* OP_RESERVED2.swift */, 348C110521D68F2B00295370 /* OP_EQUALVERIFY.swift */, 348C110621D68F2B00295370 /* OP_OR.swift */, 348C110721D68F2B00295370 /* OP_XOR.swift */, 348C110821D68F2B00295370 /* OP_RESERVED1.swift */, ); path = "Bitwise Logic"; sourceTree = ""; }; 348C110921D68F2B00295370 /* Pseudo Words */ = { isa = PBXGroup; children = ( 348C110A21D68F2B00295370 /* OP_PUBKEYHASH.swift */, 348C110B21D68F2B00295370 /* OP_PUBKEY.swift */, 348C110C21D68F2B00295370 /* OP_INVALIDOPCODE.swift */, ); path = "Pseudo Words"; sourceTree = ""; }; 348C110D21D68F2B00295370 /* Arithmetic */ = { isa = PBXGroup; children = ( 348C110E21D68F2B00295370 /* OP_BOOLAND.swift */, 348C110F21D68F2B00295370 /* OP_SUB.swift */, 348C111021D68F2B00295370 /* OP_BOOLOR.swift */, 348C111121D68F2B00295370 /* OP_RSHIFT.swift */, 348C111221D68F2B00295370 /* OP_LSHIFT.swift */, 348C111321D68F2B00295370 /* OP_MAX.swift */, 348C111421D68F2B00295370 /* OP_ADD.swift */, 348C111521D68F2B00295370 /* OP_LESSTHAN.swift */, 348C111621D68F2B00295370 /* OP_NUMNOTEQUAL.swift */, 348C111721D68F2B00295370 /* OP_LESSTHANOREQUAL.swift */, 348C111821D68F2B00295370 /* OP_MOD.swift */, 348C111921D68F2B00295370 /* OP_MUL.swift */, 348C111A21D68F2B00295370 /* OP_DIV.swift */, 348C111B21D68F2B00295370 /* OP_GREATERTHANOREQUAL.swift */, 348C111C21D68F2B00295370 /* OP_NOT.swift */, 348C111D21D68F2B00295370 /* OP_GREATERTHAN.swift */, 348C111E21D68F2B00295370 /* OP_1ADD.swift */, 348C111F21D68F2B00295370 /* OP_WITHIN.swift */, 348C112021D68F2B00295370 /* OP_NEGATE.swift */, 348C112121D68F2B00295370 /* OP_NUMEQUALVERIFY.swift */, 348C112221D68F2B00295370 /* OP_2MUL.swift */, 348C112321D68F2B00295370 /* OP_NUMEQUAL.swift */, 348C112421D68F2B00295370 /* OP_MIN.swift */, 348C112521D68F2B00295370 /* OP_ABS.swift */, 348C112621D68F2B00295370 /* OP_2DIV.swift */, 348C112721D68F2B00295370 /* OP_1SUB.swift */, 348C112821D68F2B00295370 /* OP_0NOTEQUAL.swift */, ); path = Arithmetic; sourceTree = ""; }; 348C112921D68F2B00295370 /* Splice */ = { isa = PBXGroup; children = ( 348C112A21D68F2B00295370 /* OP_SIZE.swift */, 348C112B21D68F2B00295370 /* OP_BIN2NUM.swift */, 348C112C21D68F2B00295370 /* OP_CAT.swift */, 348C112D21D68F2B00295370 /* OP_NUM2BIN.swift */, 348C112E21D68F2B00295370 /* OP_SPLIT.swift */, ); path = Splice; sourceTree = ""; }; 348C112F21D68F2B00295370 /* Reserved Words */ = { isa = PBXGroup; children = ( 348C113021D68F2B00295370 /* OP_NOPN.swift */, ); path = "Reserved Words"; sourceTree = ""; }; 348C113121D68F2B00295370 /* Stack */ = { isa = PBXGroup; children = ( 348C113221D68F2B00295370 /* OP_2SWAP.swift */, 348C113321D68F2B00295370 /* OP_TUCK.swift */, 348C113421D68F2B00295370 /* OP_ROLL.swift */, 348C113521D68F2B00295370 /* OP_SWAP.swift */, 348C113621D68F2B00295370 /* OP_2DROP.swift */, 348C113721D68F2B00295370 /* OP_TOTALSTACK.swift */, 348C113821D68F2B00295370 /* OP_DROP.swift */, 348C113921D68F2B00295370 /* OP_DEPTH.swift */, 348C113A21D68F2B00295370 /* OP_FROMALTSTACK.swift */, 348C113B21D68F2B00295370 /* OP_2DUP.swift */, 348C113C21D68F2B00295370 /* OP_3DUP.swift */, 348C113D21D68F2B00295370 /* OP_ROT.swift */, 348C113E21D68F2B00295370 /* OP_PICK.swift */, 348C113F21D68F2B00295370 /* OP_2OVER.swift */, 348C114021D68F2B00295370 /* OP_NIP.swift */, 348C114121D68F2B00295370 /* OP_IFDUP.swift */, 348C114221D68F2B00295370 /* OP_DUP.swift */, 348C114321D68F2B00295370 /* OP_2ROT.swift */, 348C114421D68F2B00295370 /* OP_OVER.swift */, ); path = Stack; sourceTree = ""; }; 348C114521D68F2B00295370 /* Lock Time */ = { isa = PBXGroup; children = ( 348C114621D68F2B00295370 /* OP_CHECKLOCKTIMEVERIFY.swift */, 348C114721D68F2B00295370 /* OP_CHECKSEQUENCEVERIFY.swift */, ); path = "Lock Time"; sourceTree = ""; }; 348C114821D68F2B00295370 /* Push Data */ = { isa = PBXGroup; children = ( 348C114921D68F2B00295370 /* OP_RESERVED.swift */, 348C114A21D68F2B00295370 /* OP_1NEGATE.swift */, 348C114B21D68F2B00295370 /* OP_0.swift */, 348C114C21D68F2B00295370 /* OP_N.swift */, 348C114D21D68F2B00295370 /* OP_PUSHDATA.swift */, ); path = "Push Data"; sourceTree = ""; }; 348C114E21D68F2B00295370 /* Flow Control */ = { isa = PBXGroup; children = ( 348C114F21D68F2B00295370 /* OP_VER.swift */, 348C115021D68F2B00295370 /* OP_NOTIF.swift */, 348C115121D68F2B00295370 /* OP_RETURN.swift */, 348C115221D68F2B00295370 /* OP_VERIFY.swift */, 348C115321D68F2B00295370 /* OP_IF.swift */, 348C115421D68F2B00295370 /* OP_NOP.swift */, 348C115521D68F2B00295370 /* OP_ELSE.swift */, 348C115621D68F2B00295370 /* OP_VERNOTIF.swift */, 348C115721D68F2B00295370 /* OP_VERIF.swift */, 348C115821D68F2B00295370 /* OP_ENDIF.swift */, ); path = "Flow Control"; sourceTree = ""; }; 348C11C421D690DF00295370 /* Model */ = { isa = PBXGroup; children = ( 34D9CF2D22199ED300B3A625 /* UnsignedTransaction.swift */, 348C11C521D690E800295370 /* UnspendTransaction */, 34C9B1BF21E2B3E700198EAF /* TransactionInput.swift */, ); path = Model; sourceTree = ""; }; 348C11C521D690E800295370 /* UnspendTransaction */ = { isa = PBXGroup; children = ( 348C10E621D68A2600295370 /* UnspendTransaction.swift */, 348C10E821D68A3400295370 /* TransactionOutput.swift */, 348C10EA21D68A4100295370 /* TransactionOutPoint.swift */, ); path = UnspendTransaction; sourceTree = ""; }; 348C11C621D6919D00295370 /* AccountBased */ = { isa = PBXGroup; children = ( 34A532302158E64200B95C66 /* ERC20 */, 3492215220F6AB4F00A59A6F /* Ethereum */, ); path = AccountBased; sourceTree = ""; }; 348C11C721D691F700295370 /* UTXOBased */ = { isa = PBXGroup; children = ( 34D9CF44221C433500B3A625 /* Constants */, 34D9CF43221C42D700B3A625 /* Default */, 348C11C421D690DF00295370 /* Model */, 34D9CF31221C36B200B3A625 /* Protocols */, 3437FD9B227846E5000B1527 /* BitcoinCash */, 348C10E121D642CB00295370 /* Bitcoin */, 34C9B1C721E5087900198EAF /* Transaction.swift */, 34D9CF2F221C361D00B3A625 /* UTXOWallet.swift */, 345B813122675002000E3460 /* UtxoPrivateKeyType.swift */, ); path = UTXOBased; sourceTree = ""; }; 348FA3BD224A4F6E00DA3F1B /* UTXO */ = { isa = PBXGroup; children = ( 348FA3BB224A4C9D00DA3F1B /* UTXOSign.swift */, ); path = UTXO; sourceTree = ""; }; 349220DC20F64C6600A59A6F = { isa = PBXGroup; children = ( 3492211920F64D9B00A59A6F /* HDWalletKit */, 3492214820F64E0300A59A6F /* HDWalletKit_Tests */, 349220E620F64C6600A59A6F /* Products */, 77307DFD3336DD82DE6F1509 /* Pods */, 4C50FFAFC17638B67FA3B603 /* Frameworks */, ); sourceTree = ""; }; 349220E620F64C6600A59A6F /* Products */ = { isa = PBXGroup; children = ( 349220E520F64C6600A59A6F /* libHDWalletKit.a */, 3492214720F64E0300A59A6F /* HDWalletKit_Tests.xctest */, ); name = Products; sourceTree = ""; }; 3492211920F64D9B00A59A6F /* HDWalletKit */ = { isa = PBXGroup; children = ( 34B7964821282BD4000B1251 /* Keystore */, 3492211A20F64D9B00A59A6F /* Core */, 3492212920F64D9B00A59A6F /* Mnemonic */, 3492212C20F64D9B00A59A6F /* Models */, 3492212E20F64D9B00A59A6F /* Wallet */, ); path = HDWalletKit; sourceTree = ""; }; 3492211A20F64D9B00A59A6F /* Core */ = { isa = PBXGroup; children = ( 348C10ED21D68F2B00295370 /* BitcoinScript */, 34753F77216E76720025E0F4 /* Converter */, 34B7B85520F7847000D2C34A /* Extensions */, 3492216720F7464700A59A6F /* Error */, 3492211B20F64D9B00A59A6F /* BigInt */, 3492211E20F64D9B00A59A6F /* Crypto */, 3492212420F64D9B00A59A6F /* DataConvertable.swift */, 3492212520F64D9B00A59A6F /* DerivationNode.swift */, 3492212620F64D9B00A59A6F /* Encodeing */, 3492216120F6B53300A59A6F /* Typealiaces.swift */, 34C9B1B721E2B06300198EAF /* ByteStream.swift */, 34C9B1B921E2B09500198EAF /* VarInt.swift */, 34C9B1BB21E2B0D400198EAF /* VarString.swift */, ); path = Core; sourceTree = ""; }; 3492211B20F64D9B00A59A6F /* BigInt */ = { isa = PBXGroup; children = ( 3492211C20F64D9B00A59A6F /* BigInt+Extension.swift */, 3492211D20F64D9B00A59A6F /* SMP.swift */, 34C9B1B521E2AE6700198EAF /* BigNumber.swift */, ); path = BigInt; sourceTree = ""; }; 3492211E20F64D9B00A59A6F /* Crypto */ = { isa = PBXGroup; children = ( 3492211F20F64D9B00A59A6F /* Encryption */, 3492212220F64D9B00A59A6F /* Hash */, ); path = Crypto; sourceTree = ""; }; 3492211F20F64D9B00A59A6F /* Encryption */ = { isa = PBXGroup; children = ( 3492216320F6B79300A59A6F /* EIP155Signer.swift */, 3492212020F64D9B00A59A6F /* Crypto.swift */, 3492212120F64D9B00A59A6F /* ECDSA.swift */, 3492216A20F747EC00A59A6F /* EllipticCurveEncrypterSecp256k1.swift */, 3401AF6D20F908AA006DEF49 /* SecpResult.swift */, ); path = Encryption; sourceTree = ""; }; 3492212220F64D9B00A59A6F /* Hash */ = { isa = PBXGroup; children = ( 3492212320F64D9B00A59A6F /* RIPEMD160.swift */, ); path = Hash; sourceTree = ""; }; 3492212620F64D9B00A59A6F /* Encodeing */ = { isa = PBXGroup; children = ( 3492216420F6B79400A59A6F /* RLP.swift */, 3492212720F64D9B00A59A6F /* Base58Encode.swift */, 3492212820F64D9B00A59A6F /* EIP55.swift */, 34D9CC432209BFAF00B3A625 /* Bech32.swift */, ); path = Encodeing; sourceTree = ""; }; 3492212920F64D9B00A59A6F /* Mnemonic */ = { isa = PBXGroup; children = ( 3492212A20F64D9B00A59A6F /* Mnemonic.swift */, 3492212B20F64D9B00A59A6F /* WordList.swift */, ); path = Mnemonic; sourceTree = ""; }; 3492212C20F64D9B00A59A6F /* Models */ = { isa = PBXGroup; children = ( 3492212D20F64D9B00A59A6F /* Account.swift */, ); path = Models; sourceTree = ""; }; 3492212E20F64D9B00A59A6F /* Wallet */ = { isa = PBXGroup; children = ( 348C11C721D691F700295370 /* UTXOBased */, 348C11C621D6919D00295370 /* AccountBased */, 3492213020F64D9B00A59A6F /* PrivateKey.swift */, 3492213220F64D9B00A59A6F /* Wallet.swift */, 3411AEE62164278A00AB9476 /* Coin.swift */, 3411AF0921656F0700AB9476 /* PublicKey.swift */, ); path = Wallet; sourceTree = ""; }; 3492214820F64E0300A59A6F /* HDWalletKit_Tests */ = { isa = PBXGroup; children = ( 348FA3BD224A4F6E00DA3F1B /* UTXO */, 34B7B84E20F75DBF00D2C34A /* MnemonicTests.swift */, 34B7B85020F75E4E00D2C34A /* CryptoTests.swift */, 34B7B85220F75E5B00D2C34A /* AddressGenerationTests.swift */, 3492214B20F64E0300A59A6F /* Info.plist */, 344167EB212CC100008B8A91 /* KeystoreTests.swift */, 34A5322D215307DF00B95C66 /* SignTransactionTests.swift */, 34A532332158E96C00B95C66 /* ERC20Tests.swift */, 34753F7A216E78430025E0F4 /* ConverterTests.swift */, 345639C9226F0CF000ED17DA /* RIPEMD160Tests.swift */, 345639CF226F58BD00ED17DA /* Secp256k1Tets.swift */, 345B81332268A649000E3460 /* PrivateKeyTests.swift */, 342233B9227E7B7600C89968 /* ImportWalletTests.swift */, ); path = HDWalletKit_Tests; sourceTree = ""; }; 3492215220F6AB4F00A59A6F /* Ethereum */ = { isa = PBXGroup; children = ( 3492215320F6B4B400A59A6F /* Model */, ); path = Ethereum; sourceTree = ""; }; 3492215320F6B4B400A59A6F /* Model */ = { isa = PBXGroup; children = ( 3401AEF920F797CB006DEF49 /* EthereumAddress.swift */, 3492215720F6B4B400A59A6F /* EthereumRawTransaction.swift */, ); path = Model; sourceTree = ""; }; 3492216720F7464700A59A6F /* Error */ = { isa = PBXGroup; children = ( 3492216820F7466800A59A6F /* HDWalletKitError.swift */, ); path = Error; sourceTree = ""; }; 34A532302158E64200B95C66 /* ERC20 */ = { isa = PBXGroup; children = ( 34A532312158E66900B95C66 /* ERC20.swift */, ); path = ERC20; sourceTree = ""; }; 34B7964821282BD4000B1251 /* Keystore */ = { isa = PBXGroup; children = ( 34B7964921296427000B1251 /* KeystoreV3Json.swift */, 34B7964B212A881C000B1251 /* KeystoreInterface.swift */, 34B7964D212A93A0000B1251 /* KeystoreV3.swift */, ); path = Keystore; sourceTree = ""; }; 34B7B85520F7847000D2C34A /* Extensions */ = { isa = PBXGroup; children = ( 34B7B85620F7848D00D2C34A /* String+Hex.swift */, 34B7964F212A95D5000B1251 /* Data+Random.swift */, 348C11C821DFDB9400295370 /* Data+Script.swift */, ); path = Extensions; sourceTree = ""; }; 34D9CF31221C36B200B3A625 /* Protocols */ = { isa = PBXGroup; children = ( 34D9CF34221C3A9900B3A625 /* UtxoSelectorInterface.swift */, 34D9CF36221C3AAF00B3A625 /* UtxoTransactionBuilderInterface.swift */, 34D9CF38221C3AC100B3A625 /* UtxoTransactionSignerInterface.swift */, ); path = Protocols; sourceTree = ""; }; 34D9CF43221C42D700B3A625 /* Default */ = { isa = PBXGroup; children = ( 34D9CF2B22199E6000B3A625 /* UtxoTransactionBuilder.swift */, 34D9CC492212FE9D00B3A625 /* UtxoSelector.swift */, 34D9CF47221C447D00B3A625 /* UtxoTransactionSigner.swift */, ); path = Default; sourceTree = ""; }; 34D9CF44221C433500B3A625 /* Constants */ = { isa = PBXGroup; children = ( 34C9B1BD21E2B38B00198EAF /* SighashType.swift */, 348C11CA21E1675B00295370 /* UtilsAndLimits.swift */, ); path = Constants; sourceTree = ""; }; 4C50FFAFC17638B67FA3B603 /* Frameworks */ = { isa = PBXGroup; children = ( 345639CD226F42BC00ED17DA /* CryptoSwift.framework */, 345639CB226F42A500ED17DA /* CryptoSwift.framework */, A71916E6C32DA0D7349D72D7 /* Pods_HDWalletKit.framework */, D4748DCAB4A042EBDF88023E /* Pods_HDWalletKit_Tests.framework */, 6F9CF1786FD900D725E89FE5 /* Pods_HDWalletKit_HDWalletKit_Tests.framework */, ); name = Frameworks; sourceTree = ""; }; 77307DFD3336DD82DE6F1509 /* Pods */ = { isa = PBXGroup; children = ( BF520BDF5160D0B847AED112 /* Pods-HDWalletKit.debug.xcconfig */, A241CE5210CEC9DFFCA47EA2 /* Pods-HDWalletKit.release.xcconfig */, 96ADBA88328A4BE2159563A5 /* Pods-HDWalletKit_Tests.debug.xcconfig */, 29695349E80AB7F880E24B02 /* Pods-HDWalletKit_Tests.release.xcconfig */, 24463252CD56603F58800D8F /* Pods-HDWalletKit-HDWalletKit_Tests.debug.xcconfig */, FE9481BAD6A096D7EC0A2E49 /* Pods-HDWalletKit-HDWalletKit_Tests.release.xcconfig */, ); name = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 349220E420F64C6600A59A6F /* HDWalletKit */ = { isa = PBXNativeTarget; buildConfigurationList = 349220EC20F64C6600A59A6F /* Build configuration list for PBXNativeTarget "HDWalletKit" */; buildPhases = ( 4B8D9FC1EAB0A374CC6823B3 /* [CP] Check Pods Manifest.lock */, 349220E120F64C6600A59A6F /* Sources */, 349220E220F64C6600A59A6F /* Frameworks */, 349220E320F64C6600A59A6F /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = HDWalletKit; productName = HDWalletKit; productReference = 349220E520F64C6600A59A6F /* libHDWalletKit.a */; productType = "com.apple.product-type.library.static"; }; 3492214620F64E0300A59A6F /* HDWalletKit_Tests */ = { isa = PBXNativeTarget; buildConfigurationList = 3492215120F64E0300A59A6F /* Build configuration list for PBXNativeTarget "HDWalletKit_Tests" */; buildPhases = ( A910BFEB3CDFE869EFBB423E /* [CP] Check Pods Manifest.lock */, 3492214320F64E0300A59A6F /* Sources */, 3492214420F64E0300A59A6F /* Frameworks */, 3492214520F64E0300A59A6F /* Resources */, 2D0545F275338FE57938BA97 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( 3492214E20F64E0300A59A6F /* PBXTargetDependency */, ); name = HDWalletKit_Tests; productName = HDWalletKit_Tests; productReference = 3492214720F64E0300A59A6F /* HDWalletKit_Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 349220DD20F64C6600A59A6F /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0940; LastUpgradeCheck = 0940; ORGANIZATIONNAME = Essentia; TargetAttributes = { 349220E420F64C6600A59A6F = { CreatedOnToolsVersion = 9.4.1; LastSwiftMigration = 1020; }; 3492214620F64E0300A59A6F = { CreatedOnToolsVersion = 9.4.1; LastSwiftMigration = 1020; }; }; }; buildConfigurationList = 349220E020F64C6600A59A6F /* Build configuration list for PBXProject "HDWalletKit" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 349220DC20F64C6600A59A6F; productRefGroup = 349220E620F64C6600A59A6F /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 349220E420F64C6600A59A6F /* HDWalletKit */, 3492214620F64E0300A59A6F /* HDWalletKit_Tests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 3492214520F64E0300A59A6F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 2D0545F275338FE57938BA97 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-HDWalletKit-HDWalletKit_Tests/Pods-HDWalletKit-HDWalletKit_Tests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-HDWalletKit-HDWalletKit_Tests/Pods-HDWalletKit-HDWalletKit_Tests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-HDWalletKit-HDWalletKit_Tests/Pods-HDWalletKit-HDWalletKit_Tests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 4B8D9FC1EAB0A374CC6823B3 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-HDWalletKit-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; A910BFEB3CDFE869EFBB423E /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-HDWalletKit-HDWalletKit_Tests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 349220E120F64C6600A59A6F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 348C116321D68F2B00295370 /* OP_HASH160.swift in Sources */, 34B7B84D20F7572900D2C34A /* HDWalletKitError.swift in Sources */, 348C11B621D68F2C00295370 /* OP_VERIFY.swift in Sources */, 348C118121D68F2B00295370 /* OP_LESSTHANOREQUAL.swift in Sources */, 348C117021D68F2B00295370 /* OP_RESERVED2.swift in Sources */, 3492216220F6B53300A59A6F /* Typealiaces.swift in Sources */, 348C117F21D68F2B00295370 /* OP_LESSTHAN.swift in Sources */, 34B7964A21296427000B1251 /* KeystoreV3Json.swift in Sources */, 348C115F21D68F2B00295370 /* ScriptFactory.swift in Sources */, 34C9B1BE21E2B38B00198EAF /* SighashType.swift in Sources */, 348C116921D68F2B00295370 /* OP_CODESEPARATOR.swift in Sources */, 3492214220F64D9B00A59A6F /* Wallet.swift in Sources */, 348C11AA21D68F2C00295370 /* OP_2ROT.swift in Sources */, 34B7964C212A881C000B1251 /* KeystoreInterface.swift in Sources */, 348C11B821D68F2C00295370 /* OP_NOP.swift in Sources */, 3492216520F6B79400A59A6F /* EIP155Signer.swift in Sources */, 348C118521D68F2B00295370 /* OP_GREATERTHANOREQUAL.swift in Sources */, 348C11BC21D68F2C00295370 /* OP_ENDIF.swift in Sources */, 348C11AF21D68F2C00295370 /* OP_1NEGATE.swift in Sources */, 348C11BA21D68F2C00295370 /* OP_VERNOTIF.swift in Sources */, 3492213B20F64D9B00A59A6F /* EIP55.swift in Sources */, 348C11B021D68F2C00295370 /* OP_0.swift in Sources */, 348C11A621D68F2C00295370 /* OP_2OVER.swift in Sources */, 348C118D21D68F2B00295370 /* OP_NUMEQUAL.swift in Sources */, 348C11AC21D68F2C00295370 /* OP_CHECKLOCKTIMEVERIFY.swift in Sources */, 34D9CC4A2212FE9D00B3A625 /* UtxoSelector.swift in Sources */, 348C119221D68F2C00295370 /* OP_0NOTEQUAL.swift in Sources */, 3401AEFA20F797CB006DEF49 /* EthereumAddress.swift in Sources */, 3492215D20F6B4B600A59A6F /* EthereumRawTransaction.swift in Sources */, 348C119921D68F2C00295370 /* OP_2SWAP.swift in Sources */, 348C119F21D68F2C00295370 /* OP_DROP.swift in Sources */, 348C11C021D68F2C00295370 /* ScriptMachine.swift in Sources */, 348C119E21D68F2C00295370 /* OP_TOTALSTACK.swift in Sources */, 348C115D21D68F2B00295370 /* OpCodeProtocol.swift in Sources */, 3492213D20F64D9B00A59A6F /* WordList.swift in Sources */, 348C118721D68F2B00295370 /* OP_GREATERTHAN.swift in Sources */, 3411AF0A21656F0700AB9476 /* PublicKey.swift in Sources */, 348C10E721D68A2600295370 /* UnspendTransaction.swift in Sources */, 348C116621D68F2B00295370 /* OP_CHECKMULTISIG.swift in Sources */, 348C118821D68F2B00295370 /* OP_1ADD.swift in Sources */, 348C11AB21D68F2C00295370 /* OP_OVER.swift in Sources */, 348C119621D68F2C00295370 /* OP_NUM2BIN.swift in Sources */, 348C11B121D68F2C00295370 /* OP_N.swift in Sources */, 348C116221D68F2B00295370 /* OP_SHA1.swift in Sources */, 348C119821D68F2C00295370 /* OP_NOPN.swift in Sources */, 348C116B21D68F2B00295370 /* OP_HASH256.swift in Sources */, 34B7B85720F7848D00D2C34A /* String+Hex.swift in Sources */, 348C118F21D68F2B00295370 /* OP_ABS.swift in Sources */, 348C118E21D68F2B00295370 /* OP_MIN.swift in Sources */, 348C117C21D68F2B00295370 /* OP_LSHIFT.swift in Sources */, 348C11AE21D68F2C00295370 /* OP_RESERVED.swift in Sources */, 3492213720F64D9B00A59A6F /* RIPEMD160.swift in Sources */, 3492213920F64D9B00A59A6F /* DerivationNode.swift in Sources */, 348C117E21D68F2B00295370 /* OP_ADD.swift in Sources */, 3401AF6E20F908AA006DEF49 /* SecpResult.swift in Sources */, 348C119C21D68F2C00295370 /* OP_SWAP.swift in Sources */, 34C9B1CA21E50A1700198EAF /* BitcoinCashVersionByte.swift in Sources */, 348C117A21D68F2B00295370 /* OP_BOOLOR.swift in Sources */, 348C11A321D68F2C00295370 /* OP_3DUP.swift in Sources */, 348C116121D68F2B00295370 /* ScriptChunkHelper.swift in Sources */, 348C116721D68F2B00295370 /* OP_CHECKSIGVERIFY.swift in Sources */, 348C11B421D68F2C00295370 /* OP_NOTIF.swift in Sources */, 3492213820F64D9B00A59A6F /* DataConvertable.swift in Sources */, 348C11B321D68F2C00295370 /* OP_VER.swift in Sources */, 348C11A021D68F2C00295370 /* OP_DEPTH.swift in Sources */, 348C11A221D68F2C00295370 /* OP_2DUP.swift in Sources */, 34D9CF2E22199ED300B3A625 /* UnsignedTransaction.swift in Sources */, 3492213E20F64D9B00A59A6F /* Account.swift in Sources */, 348C119D21D68F2C00295370 /* OP_2DROP.swift in Sources */, 348C117321D68F2B00295370 /* OP_XOR.swift in Sources */, 348C116A21D68F2B00295370 /* OP_CHECKSIG.swift in Sources */, 34B79650212A95D5000B1251 /* Data+Random.swift in Sources */, 3411D0D82279FD3E0016D0C8 /* BitcoinCashAddress.swift in Sources */, 348C119321D68F2C00295370 /* OP_SIZE.swift in Sources */, 348C117621D68F2B00295370 /* OP_PUBKEY.swift in Sources */, 348C118421D68F2B00295370 /* OP_DIV.swift in Sources */, 348C116F21D68F2B00295370 /* OP_EQUAL.swift in Sources */, 348C11A721D68F2C00295370 /* OP_NIP.swift in Sources */, 348C11A121D68F2C00295370 /* OP_FROMALTSTACK.swift in Sources */, 348C117521D68F2B00295370 /* OP_PUBKEYHASH.swift in Sources */, 348C118221D68F2B00295370 /* OP_MOD.swift in Sources */, 3411AEE72164278A00AB9476 /* Coin.swift in Sources */, 348C119B21D68F2C00295370 /* OP_ROLL.swift in Sources */, 348C118921D68F2B00295370 /* OP_WITHIN.swift in Sources */, 348C11BB21D68F2C00295370 /* OP_VERIF.swift in Sources */, 348C11BD21D68F2C00295370 /* Opcode.swift in Sources */, 34C9B1BA21E2B09500198EAF /* VarInt.swift in Sources */, 34D9CF2C22199E6000B3A625 /* UtxoTransactionBuilder.swift in Sources */, 348C11A521D68F2C00295370 /* OP_PICK.swift in Sources */, 348C118021D68F2B00295370 /* OP_NUMNOTEQUAL.swift in Sources */, 34C9B1C021E2B3E700198EAF /* TransactionInput.swift in Sources */, 34C9B1B621E2AE6700198EAF /* BigNumber.swift in Sources */, 3492213A20F64D9B00A59A6F /* Base58Encode.swift in Sources */, 34D9CC442209BFAF00B3A625 /* Bech32.swift in Sources */, 345B813222675002000E3460 /* UtxoPrivateKeyType.swift in Sources */, 34D9CF39221C3AC100B3A625 /* UtxoTransactionSignerInterface.swift in Sources */, 3492213520F64D9B00A59A6F /* Crypto.swift in Sources */, 34A532322158E66900B95C66 /* ERC20.swift in Sources */, 348C117221D68F2B00295370 /* OP_OR.swift in Sources */, 348C118B21D68F2B00295370 /* OP_NUMEQUALVERIFY.swift in Sources */, 348C119121D68F2C00295370 /* OP_1SUB.swift in Sources */, 348C116421D68F2B00295370 /* OP_SHA256.swift in Sources */, 348C11A421D68F2C00295370 /* OP_ROT.swift in Sources */, 348C11BF21D68F2C00295370 /* Script.swift in Sources */, 3492216B20F747EC00A59A6F /* EllipticCurveEncrypterSecp256k1.swift in Sources */, 3492213420F64D9B00A59A6F /* SMP.swift in Sources */, 3492216620F6B79400A59A6F /* RLP.swift in Sources */, 348C11B221D68F2C00295370 /* OP_PUSHDATA.swift in Sources */, 34C9B1C221E5065000198EAF /* BitcoinAddress.swift in Sources */, 348C117921D68F2B00295370 /* OP_SUB.swift in Sources */, 348C116521D68F2B00295370 /* OP_CHECKMULTISIGVERIFY.swift in Sources */, 3492213620F64D9B00A59A6F /* ECDSA.swift in Sources */, 34753F79216E76B70025E0F4 /* WeiEthterConverter.swift in Sources */, 348C11BE21D68F2C00295370 /* OpCodeFactory.swift in Sources */, 348C119A21D68F2C00295370 /* OP_TUCK.swift in Sources */, 348C117721D68F2B00295370 /* OP_INVALIDOPCODE.swift in Sources */, 348C10EB21D68A4100295370 /* TransactionOutPoint.swift in Sources */, 348C117421D68F2B00295370 /* OP_RESERVED1.swift in Sources */, 34C9B1B821E2B06300198EAF /* ByteStream.swift in Sources */, 348C118621D68F2B00295370 /* OP_NOT.swift in Sources */, 348C11B921D68F2C00295370 /* OP_ELSE.swift in Sources */, 348C11A821D68F2C00295370 /* OP_IFDUP.swift in Sources */, 348C11AD21D68F2C00295370 /* OP_CHECKSEQUENCEVERIFY.swift in Sources */, 3492213320F64D9B00A59A6F /* BigInt+Extension.swift in Sources */, 348C119021D68F2B00295370 /* OP_2DIV.swift in Sources */, 348C117121D68F2B00295370 /* OP_EQUALVERIFY.swift in Sources */, 34D9CF30221C361D00B3A625 /* UTXOWallet.swift in Sources */, 34D9CF35221C3A9900B3A625 /* UtxoSelectorInterface.swift in Sources */, 348C11CB21E1675B00295370 /* UtilsAndLimits.swift in Sources */, 34D9CF48221C447D00B3A625 /* UtxoTransactionSigner.swift in Sources */, 348C11B521D68F2C00295370 /* OP_RETURN.swift in Sources */, 348C119521D68F2C00295370 /* OP_CAT.swift in Sources */, 348C116D21D68F2B00295370 /* OP_AND.swift in Sources */, 348C116821D68F2B00295370 /* OP_RIPEMD160.swift in Sources */, 348C118321D68F2B00295370 /* OP_MUL.swift in Sources */, 34D9CC462209CD4300B3A625 /* Transaction+SignatureHash.swift in Sources */, 348C115E21D68F2B00295370 /* ScriptChunk.swift in Sources */, 348C117D21D68F2B00295370 /* OP_MAX.swift in Sources */, 34C9B1C821E5087900198EAF /* Transaction.swift in Sources */, 3492213C20F64D9B00A59A6F /* Mnemonic.swift in Sources */, 348C119721D68F2C00295370 /* OP_SPLIT.swift in Sources */, 348C119421D68F2C00295370 /* OP_BIN2NUM.swift in Sources */, 34D9CC482209CDB900B3A625 /* BitcoinTransactionSignatureSerializer.swift in Sources */, 348C11B721D68F2C00295370 /* OP_IF.swift in Sources */, 348C11A921D68F2C00295370 /* OP_DUP.swift in Sources */, 348C10E921D68A3400295370 /* TransactionOutput.swift in Sources */, 348C117821D68F2B00295370 /* OP_BOOLAND.swift in Sources */, 348C116C21D68F2B00295370 /* OP_EXAMPLE.swift in Sources */, 348C11C921DFDB9400295370 /* Data+Script.swift in Sources */, 348C116E21D68F2B00295370 /* OP_INVERT.swift in Sources */, 348C117B21D68F2B00295370 /* OP_RSHIFT.swift in Sources */, 34C9B1BC21E2B0D400198EAF /* VarString.swift in Sources */, 34B7964E212A93A0000B1251 /* KeystoreV3.swift in Sources */, 348C118C21D68F2B00295370 /* OP_2MUL.swift in Sources */, 34D9CF37221C3AAF00B3A625 /* UtxoTransactionBuilderInterface.swift in Sources */, 3492214020F64D9B00A59A6F /* PrivateKey.swift in Sources */, 348C116021D68F2B00295370 /* ScriptExecutionContext.swift in Sources */, 348C118A21D68F2B00295370 /* OP_NEGATE.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 3492214320F64E0300A59A6F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 34A5322E215307DF00B95C66 /* SignTransactionTests.swift in Sources */, 34B7B85320F75E5B00D2C34A /* AddressGenerationTests.swift in Sources */, 345639CA226F0CF000ED17DA /* RIPEMD160Tests.swift in Sources */, 348FA3BC224A4C9D00DA3F1B /* UTXOSign.swift in Sources */, 34B7B85120F75E4E00D2C34A /* CryptoTests.swift in Sources */, 342233BA227E7B7600C89968 /* ImportWalletTests.swift in Sources */, 34B7B84F20F75DBF00D2C34A /* MnemonicTests.swift in Sources */, 34753F7B216E78430025E0F4 /* ConverterTests.swift in Sources */, 34A532342158E96C00B95C66 /* ERC20Tests.swift in Sources */, 345639D0226F58BD00ED17DA /* Secp256k1Tets.swift in Sources */, 344167EC212CC100008B8A91 /* KeystoreTests.swift in Sources */, 345B81342268A649000E3460 /* PrivateKeyTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 3492214E20F64E0300A59A6F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 349220E420F64C6600A59A6F /* HDWalletKit */; targetProxy = 3492214D20F64E0300A59A6F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 349220EA20F64C6600A59A6F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.4; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; }; name = Debug; }; 349220EB20F64C6600A59A6F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.4; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2; VALIDATE_PRODUCT = YES; }; name = Release; }; 349220ED20F64C6600A59A6F /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = BF520BDF5160D0B847AED112 /* Pods-HDWalletKit.debug.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = X24R65DM8E; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "'@executable_path/Frameworks'", "'@loader_path/Frameworks'", "'@executable_path/../../Frameworks'", "@loader_path", ); OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 349220EE20F64C6600A59A6F /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = A241CE5210CEC9DFFCA47EA2 /* Pods-HDWalletKit.release.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = X24R65DM8E; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "'@executable_path/Frameworks'", "'@loader_path/Frameworks'", "'@executable_path/../../Frameworks'", "@loader_path", ); OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; 3492214F20F64E0300A59A6F /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 24463252CD56603F58800D8F /* Pods-HDWalletKit-HDWalletKit_Tests.debug.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = P8JA7643K4; INFOPLIST_FILE = HDWalletKit_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "Essentia.HDWalletKit-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 3492215020F64E0300A59A6F /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = FE9481BAD6A096D7EC0A2E49 /* Pods-HDWalletKit-HDWalletKit_Tests.release.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = P8JA7643K4; INFOPLIST_FILE = HDWalletKit_Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "Essentia.HDWalletKit-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 349220E020F64C6600A59A6F /* Build configuration list for PBXProject "HDWalletKit" */ = { isa = XCConfigurationList; buildConfigurations = ( 349220EA20F64C6600A59A6F /* Debug */, 349220EB20F64C6600A59A6F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 349220EC20F64C6600A59A6F /* Build configuration list for PBXNativeTarget "HDWalletKit" */ = { isa = XCConfigurationList; buildConfigurations = ( 349220ED20F64C6600A59A6F /* Debug */, 349220EE20F64C6600A59A6F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3492215120F64E0300A59A6F /* Build configuration list for PBXNativeTarget "HDWalletKit_Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( 3492214F20F64E0300A59A6F /* Debug */, 3492215020F64E0300A59A6F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 349220DD20F64C6600A59A6F /* Project object */; } ================================================ FILE: HDWalletKit.xcodeproj/xcshareddata/xcschemes/HDWalletKit.xcscheme ================================================ ================================================ FILE: HDWalletKit.xcodeproj/xcshareddata/xcschemes/HDWalletKit_Tests.xcscheme ================================================ ================================================ FILE: HDWalletKit_Tests/AddressGenerationTests.swift ================================================ // // AddressGenerationTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 12.07.18. // Copyright © 2018 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class AddressGenerationTests: XCTestCase { func testMainnetChildKeyDerivation() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let privateKey = PrivateKey(seed: seed, coin: .bitcoin) // BIP44 key derivation // m/44' let purpose = privateKey.derived(at: .hardened(44)) // m/44'/0' let coinType = purpose.derived(at: .hardened(0)) // m/44'/0'/0' let account = coinType.derived(at: .hardened(0)) // m/44'/0'/0'/0 let change = account.derived(at: .notHardened(0)) // m/44'/0'/0'/0/0 let firstPrivateKey = change.derived(at: .notHardened(0)) XCTAssertEqual( firstPrivateKey.publicKey.address, "128BCBZndgrPXzEgF4QbVR3jnQGwzRtEz5" ) XCTAssertEqual( firstPrivateKey.publicKey.compressedPublicKey.toHexString(), "03ce9b978595558053580d557ff40f9f99a4f1a7609c25268863ee64de7e4abbda" ) } func testBitcoinMainNetAddressGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let wallet = Wallet(seed: seed, coin: .bitcoin) let firstAccount = wallet.generateAccount(at: 0) XCTAssertEqual(firstAccount.address, "128BCBZndgrPXzEgF4QbVR3jnQGwzRtEz5") XCTAssertEqual(firstAccount.rawPublicKey, "03ce9b978595558053580d557ff40f9f99a4f1a7609c25268863ee64de7e4abbda") XCTAssertEqual(firstAccount.rawPrivateKey, "L35qaFLpbCc9yCzeTuWJg4qWnTs9BaLr5CDYcnJ5UnGmgLo8JBgk") let secondAddress = wallet.generateAddress(at: 1) XCTAssertEqual(secondAddress, "1E7NvpF3u87rbpfYxt3HDmpFasPiU2JhMp") let thirdAddress = wallet.generateAddress(at: 2) XCTAssertEqual(thirdAddress, "12KtZ5SXaQGT2iL89VoFQMuuutPUwXmqdL") let forthAddress = wallet.generateAddress(at: 3) XCTAssertEqual(forthAddress, "1NPN2MZ2iKK4a1Bav8D4MHYVG6mTetV8xb") } func testEthereumAddressGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let wallet = Wallet(seed: seed, coin: .ethereum) let firstAccount = wallet.generateAccount(at: 0) XCTAssertEqual(firstAccount.address, "0x83f1caAdaBeEC2945b73087F803d404F054Cc2B7") XCTAssertEqual(firstAccount.rawPublicKey, "039966a68158fcf8839e7bdbc6b889d4608bd0b4afb358b073bed1d7b70dbe2f4f") XCTAssertEqual(firstAccount.rawPrivateKey, "df02cbea58239744a8a6ba328056309ae43f86fec6db45e5f782adcf38aacadf") } func testLitecoinAddressGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let wallet = Wallet(seed: seed, coin: .litecoin) let firstAccount = wallet.generateAccount(at: 0) XCTAssertEqual(firstAccount.address, "LV8fThzQw45HT6bCgs1yfvLNzv4aFvjJt1") XCTAssertEqual(firstAccount.rawPublicKey, "026eeb12b93ab20b32970e2fa0e7fbaa97f9016dc743ad3efc922681ce33adc40d") XCTAssertEqual(firstAccount.rawPrivateKey, "T3d12aqL7XSNqMojMtqBZGhQ6E93dzrdbnNUKMvdmVTa9TQn4L3m") let secondAddress = wallet.generateAddress(at: 1) XCTAssertEqual(secondAddress, "Lg7bkp36nPJdqoYAfpmR1UUdXgSq9iCxBX") let thirdAddress = wallet.generateAddress(at: 2) XCTAssertEqual(thirdAddress, "LRajgVNRke9ttvrnncpH52iNAbCFdSxq2b") let forthAddress = wallet.generateAddress(at: 3) XCTAssertEqual(forthAddress, "LcZoNSHLQc1XGjMLy6PdqE8PtphMbRPCQ3") } func testDashAddressGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let wallet = Wallet(seed: seed, coin: .dash) let firstAccount = wallet.generateAccount(at: 0) XCTAssertEqual(firstAccount.address, "Xud1fZjupDuhndpYtTquDPmSWmehtEbxhy") XCTAssertEqual(firstAccount.rawPublicKey, "02f1dfce053d0a9aadb8f63ab4490ac84b33ad018c62dbabb9ff2352fe62fc4619") XCTAssertEqual(firstAccount.rawPrivateKey, "XCHbiHeTfzwhryHEZTp3ojAM1nYpKwL575ieLLv7s4q1f5ZEm1vP") let secondAddress = wallet.generateAddress(at: 1) XCTAssertEqual(secondAddress, "XbATV62bhk2P1Vkroc1QXX3vqJuSxvvDta") let thirdAddress = wallet.generateAddress(at: 2) XCTAssertEqual(thirdAddress, "XoWa4HnW9u8fWQHaAPH9YirPcUZVVEdMMk") let forthAddress = wallet.generateAddress(at: 3) XCTAssertEqual(forthAddress, "XnckifVkTXKkSQf3k7LKPVYaVfycuXQhZ6") } func testDogecoinAddressGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let wallet = Wallet(seed: seed, coin: .dogecoin) let firstAccount = wallet.generateAccount(at: 0) XCTAssertEqual(firstAccount.address, "DSsPuTmCThdr1qkgJ49K1mHskypbi2LTrS") XCTAssertEqual(firstAccount.rawPublicKey, "0372caf38ff987350d04a24cad8436b3c9337d9bc0ebab2a39682d621c34ddc99b") XCTAssertEqual(firstAccount.rawPrivateKey, "6KJYQ2MeVTWDA7gA9YCGn2GpHwe4679QY874nLmp6U1jjHgDnHg") let secondAddress = wallet.generateAddress(at: 1) XCTAssertEqual(secondAddress, "DCvD62aLgZSuAvSxbFPyyLaaSHjFNAmDye") let thirdAddress = wallet.generateAddress(at: 2) XCTAssertEqual(thirdAddress, "DRa2dkLbiezQ23ubYbjUwgJRZff1GHpT7p") let forthAddress = wallet.generateAddress(at: 3) XCTAssertEqual(forthAddress, "D99a5gvcaWxy5fugLymc629j8bBX33KPo9") } func testBitcoinCashAddressGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let wallet = Wallet(seed: seed, coin: .bitcoinCash) let firstAccount = wallet.generateAccount(at: 0) XCTAssertEqual(firstAccount.address, "1FYh9oXWbAzgcX3hPSrRWUodYWt87bMmne") XCTAssertEqual(firstAccount.privateKey.publicKey.generateCashAddress(), "bitcoincash:qz0eqtpupzxvx5h2u93tew8mq4qtglyhzyjdq3ezw0") XCTAssertEqual(firstAccount.rawPublicKey, "030f6c58f37ffe1bf56dd79fac07f339f44d96efaa3d78e1f32fadd41dcd0b7bbc") XCTAssertEqual(firstAccount.rawPrivateKey, "KwgDcj2ZDN5vzRXsTv1F6vzQV7nx7shEYjFBcWng1sH6Fy9rhK2b") let secondAccount = wallet.generateAccount(at: 1) XCTAssertEqual(secondAccount.address, "19Q2M5swtorWmL9ZdhtaxBFFuhUuBr9z1Q") XCTAssertEqual(secondAccount.privateKey.publicKey.generateCashAddress(), "bitcoincash:qpwphvnuxqxxg9z9m4f7vkuyrzu5twjasqyfxl5x3g") let thirdAccount = wallet.generateAccount(at: 2) XCTAssertEqual(thirdAccount.address, "1QDAX8eZXMjVdZxMzHyXr81uWu9ZDWd9vR") XCTAssertEqual(thirdAccount.privateKey.publicKey.generateCashAddress(), "bitcoincash:qrlf04xqfxaum4w7dsk7s8q5utulazggfunjpz7tes") let forthAccount = wallet.generateAccount(at: 3) XCTAssertEqual(forthAccount.address, "1Jgjm6m4ETPGezaoTBdJCJV7RCjDRR9Ddf") XCTAssertEqual(forthAccount.privateKey.publicKey.generateCashAddress(), "bitcoincash:qrqlur3v8zl500w8k5lkas4re7d70zmxtqnqp5htct") } func testBitcoinMainNetAccountGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let wallet = Wallet(seed: seed, coin: .bitcoin) let privateKey0 = bip44PrivateKey(coin: wallet.coin, from:wallet.privateKey).derived(at: .notHardened(0)) let privateKey1 = bip44PrivateKey(coin: wallet.coin, from:wallet.privateKey).derived(at: .notHardened(1)) let accounts:[String] = [Account(privateKey: privateKey0), Account(privateKey: privateKey1)].compactMap { (account) -> String in return account.address } let generatedAccounts:[String] = wallet.generateAccounts(count: 2).compactMap { (account) -> String in return account.address } XCTAssertEqual(generatedAccounts, accounts) } func testBitcoinAddressFromPrivateKeyGeneration() { let privateKey = PrivateKey(pk: "L35qaFLpbCc9yCzeTuWJg4qWnTs9BaLr5CDYcnJ5UnGmgLo8JBgk", coin: .bitcoin) XCTAssertEqual(privateKey?.publicKey.address, "128BCBZndgrPXzEgF4QbVR3jnQGwzRtEz5") } func testBitcoinCashFromPrivateKeyGeneration() { let privateKey = PrivateKey(pk: "L1a13jus2Tm8rbcJX3TMenNPCtMBD19jB4krpsfCk5mmDoZZSAft", coin: .bitcoinCash) XCTAssertEqual(privateKey?.publicKey.address, "19Q2M5swtorWmL9ZdhtaxBFFuhUuBr9z1Q") XCTAssertEqual(privateKey?.publicKey.generateCashAddress(), "bitcoincash:qpwphvnuxqxxg9z9m4f7vkuyrzu5twjasqyfxl5x3g") } func testEthereumAddressFromPrivateKeyGeneration() { let privateKey = PrivateKey(pk: "df02cbea58239744a8a6ba328056309ae43f86fec6db45e5f782adcf38aacadf", coin: .ethereum) XCTAssertEqual(privateKey?.publicKey.address, "0x83f1caAdaBeEC2945b73087F803d404F054Cc2B7") } func testLitecoinAddressFromPrivateKeyGeneration() { let privateKey = PrivateKey(pk: "T3d12aqL7XSNqMojMtqBZGhQ6E93dzrdbnNUKMvdmVTa9TQn4L3m", coin: .litecoin) XCTAssertEqual(privateKey?.publicKey.address, "LV8fThzQw45HT6bCgs1yfvLNzv4aFvjJt1") } func testDashAddressFromPrivateKeyGeneration() { let privateKey = PrivateKey(pk: "XJV6uhBJu5tu34hjKK2x28t9kpMUmPH4vC9xU4RDA62Yz8oKsKac", coin: .dash) XCTAssertEqual(privateKey?.publicKey.address, "Xqe9L4R81MhQE4MX3w38zhAJyQSSiZLZXy") XCTAssertEqual(privateKey?.publicKey.address, "Xqe9L4R81MhQE4MX3w38zhAJyQSSiZLZXy") } func bip44PrivateKey(coin: Coin , from: PrivateKey) -> PrivateKey { let bip44Purpose:UInt32 = 44 let purpose = from.derived(at: .hardened(bip44Purpose)) let coinType = purpose.derived(at: .hardened(coin.coinType)) let account = coinType.derived(at: .hardened(0)) let receive = account.derived(at: .notHardened(0)) return receive } } ================================================ FILE: HDWalletKit_Tests/ConverterTests.swift ================================================ // // ConverterTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 10/10/18. // Copyright © 2018 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class ConverterTests: XCTestCase { func testConverter() { XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("100000000000000")!), 0.0001) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("1000000000000000")!), 0.001) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("10000000000000000")!), 0.01) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("100000000000000000")!), 0.1) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("1000000000000000000")!), 1) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("10000000000000000000")!), 10) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("100000000000000000000")!), 100) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("1000000000000000000000")!), 1000) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("0xDE0B6B3A7640000", radix: 16)!), 1) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("1000000000000000")!), 0.001) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("10000000000000000")!), 0.01) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("100000000000000000")!), 0.1) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("1000000000000000000")!), 1) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("10000000000000000000")!), 10) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("100000000000000000000")!), 100) XCTAssertEqual(try! WeiEthterConverter.toEther(wei: Wei("1000000000000000000000")!), 1000) XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "0.0001")!).description, "100000000000000") XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "0.001")!).description, "1000000000000000") XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "0.01")!).description, "10000000000000000") XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "0.1")!).description, "100000000000000000") XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "1")!).description, "1000000000000000000") XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "10")!).description, "10000000000000000000") XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "100")!).description, "100000000000000000000") XCTAssertEqual(try! WeiEthterConverter.toWei(ether: Ether(string: "1000")!).description, "1000000000000000000000") XCTAssertEqual(WeiEthterConverter.toWei(GWei: 1), 1000000000) XCTAssertEqual(WeiEthterConverter.toWei(GWei: 10), 10000000000) XCTAssertEqual(WeiEthterConverter.toWei(GWei: 15), 15000000000) XCTAssertEqual(WeiEthterConverter.toWei(GWei: 30), 30000000000) XCTAssertEqual(WeiEthterConverter.toWei(GWei: 60), 60000000000) XCTAssertEqual(WeiEthterConverter.toWei(GWei: 99), 99000000000) } func testTokensConvert() { XCTAssertEqual(try! WeiEthterConverter.toToken(balance: "0x2d79883d2000", decimals: 12, radix: 16).description, "50") XCTAssertEqual(try! WeiEthterConverter.toToken(balance: "50000000000000", decimals: 12, radix: 10).description, "50") } } ================================================ FILE: HDWalletKit_Tests/CryptoTests.swift ================================================ // // CryptoTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 12.07.18. // Copyright © 2018 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class CryptoTests: XCTestCase { func testSHA3Keccak256() { let data = "Hello".data(using: .utf8)! let encrypted = Crypto.sha3keccak256(data: data) XCTAssertEqual(encrypted.toHexString(), "06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2") } func testPrivateKeySign() { let signer = EIP155Signer(chainId: 1) let rawTransaction1 = EthereumRawTransaction( value: Wei("10000000000000000")!, to: "0x91c79f31De5208fadCbF83f0a7B0A9b6d8aBA90F", gasPrice: 99000000000, gasLimit: 21000, nonce: 2 ) XCTAssertEqual( try! signer.hash(rawTransaction: rawTransaction1).toHexString(), "de6ed032e8f09adb557f6a0ebc16ed52d6a75e0644a77a236aa1cfffa7746e9a" ) let rawTransaction2 = EthereumRawTransaction( value: Wei("10000000000000000")!, to: "0x88b44BC83add758A3642130619D61682282850Df", gasPrice: 99000000000, gasLimit: 200000, nonce: 4 ) XCTAssertEqual( try! signer.hash(rawTransaction: rawTransaction2).toHexString(), "b148272b2a985365e08abb17a85ca5e171169978f3b55e6852a035f83b9f3aa5" ) let rawTransaction3 = EthereumRawTransaction( value: Wei("20000000000000000")!, to: "0x72AAb5461F9bE958E1c375285CC2aA7De89D02A1", gasPrice: 99000000000, gasLimit: 21000, nonce: 25 ) XCTAssertEqual( try! signer.hash(rawTransaction: rawTransaction3).toHexString(), "280e29f030cfa256b4298a2b834a4add92b37f159b3cce1110e1ff9f7514f9fe" ) } func testGeneratingRSV() { let signature = Data(hex: "28ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa63627667cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d8300") let signer = EIP155Signer(chainId: 1) let (r, s, v) = signer.calculateRSV(signature: signature) XCTAssertEqual(r, BInt("18515461264373351373200002665853028612451056578545711640558177340181847433846")!) XCTAssertEqual(s, BInt("46948507304638947509940763649030358759909902576025900602547168820602576006531")!) XCTAssertEqual(v, BInt(37)) let restoredSignature = signer.calculateSignature(r: r, s: s, v: v) XCTAssertEqual(signature, restoredSignature) } func testRestoringSignatureSignedWithOldScheme() { let v = 27 let r = "75119860711638973245538703589762310947594328712729260330312782656531560398776" let s = "51392727032514077370236468627319183981033698696331563950328005524752791633785" let signer = EIP155Signer(chainId: 1) let signature = signer.calculateSignature(r: BInt(r)!, s: BInt(s)!, v: BInt(v)) XCTAssertEqual(signature.toHexString(), "a614559de76862bb1dbf8a969d8979e5bf21b72c51c96b27b3d247b728ebffb8719f40b018940ffd0880285d2196cdd31a710bf7cdda60c77632743d687dff7900") let r1 = "79425995431864040500581522255237765710685762616259654871112297909982135982384" let s1 = "1777326029228985739367131500591267170048497362640342741198949880105318675913" let signature1 = signer.calculateSignature(r: BInt(r1)!, s: BInt(s1)!, v: BInt(v)) XCTAssertEqual(signature1.toHexString(), "af998533cdac5d64594f462871a8ba79fe41d59295e39db3f069434c9862193003edee4e64d899a2c57bd726e972bb6fdb354e3abcd5846e2315ecfec332f5c900") } func testCreatePublicKey() { let pk = PrivateKey(pk: "L5GgBH1U8PuNuzCQGvvEH3udEXCEuJaiK96e88romhpGa1cU7JTY", coin: .bitcoin)! let publicKey = Crypto.generatePublicKey(data: pk.raw, compressed: true) XCTAssertEqual(publicKey.toHexString(), "0346a4129884b46fdb7f7977c6e90ed4c367af343494f3ff5272db721752d28ef3") } func bip44PrivateKey(coin: Coin , from: PrivateKey) -> PrivateKey { let bip44Purpose:UInt32 = 44 let purpose = from.derived(at: .hardened(bip44Purpose)) let coinType = purpose.derived(at: .hardened(coin.coinType)) let account = coinType.derived(at: .hardened(0)) let receive = account.derived(at: .notHardened(0)) return receive } func testPublickKeyHashOutFromPubKeyHash() { let expected = "76a9210392030131e97b2a396691a7c1d91f6b5541649b75bda14d056797ab3cadcaf2f588ac" let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) let privateKey = PrivateKey(seed: seed, coin: .bitcoin) let publicKey = privateKey.publicKey.data let hash = Script.buildPublicKeyHashOut(pubKeyHash: publicKey) XCTAssertEqual(hash.toHexString(), expected) } } ================================================ FILE: HDWalletKit_Tests/ERC20Tests.swift ================================================ // // ERC20Tests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 24.09.18. // Copyright © 2018 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit fileprivate enum Constants { static var ethereumAddress = "2f5059f64D5C0c4895092D26CDDacC58751e0C3C" static var smartContractAddress = "0x8f0921f30555624143d427b340b1156914882c10" } final class ERC20Tests: XCTestCase { var erc20Token: ERC20! override func setUp() { erc20Token = ERC20(contractAddress: Constants.smartContractAddress, decimal: 18, symbol: "TEST") } func testGenerateTransactionData() { let expectations = ["3": "0xa9059cbb0000000000000000000000002f5059f64d5c0c4895092d26cddacc58751e0c3c00000000000000000000000000000000000000000000000029a2241af62c0000", "0.25": "0xa9059cbb0000000000000000000000002f5059f64d5c0c4895092d26cddacc58751e0c3c00000000000000000000000000000000000000000000000003782dace9d90000", "0.155555": "0xa9059cbb0000000000000000000000002f5059f64d5c0c4895092d26cddacc58751e0c3c0000000000000000000000000000000000000000000000000228a472c6093000", "3000": "0xa9059cbb0000000000000000000000002f5059f64d5c0c4895092d26cddacc58751e0c3c0000000000000000000000000000000000000000000000a2a15d09519be00000", "9000": "0xa9059cbb0000000000000000000000002f5059f64d5c0c4895092d26cddacc58751e0c3c0000000000000000000000000000000000000000000001e7e4171bf4d3a00000"] expectations.forEach { (expectations) in calculateTransaction(with: expectations.key, expentation: expectations.value) } } func calculateTransaction(with ammount: String, expentation: String) { let data = try! erc20Token.generateSendBalanceParameter(toAddress: Constants.ethereumAddress, amount: ammount) XCTAssertEqual(data.toHexString().addHexPrefix(), expentation) } func testGenerateGetBalanceParameter() { let data = try! erc20Token.generateGetBalanceParameter(toAddress: Constants.ethereumAddress) XCTAssertEqual( data.toHexString().addHexPrefix(), "0x70a082310000000000000000000000002f5059f64d5c0c4895092d26cddacc58751e0c3c" ) } func testSignatures() { XCTAssertEqual(erc20Token.transferSignature.toHexString(), "a9059cbb") XCTAssertEqual(erc20Token.balanceSignature.toHexString(), "70a08231") } } ================================================ FILE: HDWalletKit_Tests/ImportWalletTests.swift ================================================ // // ImportWalletTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 5/5/19. // Copyright © 2019 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class ImportWalletTests: XCTestCase { func testImportBitcoinAddress() { let legacy = try! LegacyAddress("1FYh9oXWbAzgcX3hPSrRWUodYWt87bMmne", coin: .bitcoinCash) XCTAssertEqual(legacy.data.toHexString(), "9f902c3c088cc352eae162bcb8fb0540b47c9711") XCTAssertEqual(legacy.cashaddr, "bitcoincash:qz0eqtpupzxvx5h2u93tew8mq4qtglyhzyjdq3ezw0") XCTAssertEqual(legacy.base58, "1FYh9oXWbAzgcX3hPSrRWUodYWt87bMmne") } func testImportBitcoinCashAddress() { let bch = try! BitcoinCashAddress("bitcoincash:qz0eqtpupzxvx5h2u93tew8mq4qtglyhzyjdq3ezw0") XCTAssertEqual(bch.data.toHexString(), "9f902c3c088cc352eae162bcb8fb0540b47c9711") XCTAssertEqual(bch.cashaddr, "bitcoincash:qz0eqtpupzxvx5h2u93tew8mq4qtglyhzyjdq3ezw0") XCTAssertEqual(bch.base58, "1FYh9oXWbAzgcX3hPSrRWUodYWt87bMmne") } } ================================================ FILE: HDWalletKit_Tests/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleVersion 1 BuildSystemType Original ================================================ FILE: HDWalletKit_Tests/KeystoreTests.swift ================================================ // // KeystoreTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 22.08.18. // Copyright © 2018 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class KeystoreTests: XCTestCase { func testKeyStoreGeneration() { let data = Data("abandon amount liar amount expire adjust cage candy arch gather drum buyer".utf8) let passwordData = Data("qwertyui".utf8) let keystore = try! KeystoreV3(data: data, passwordData: passwordData) XCTAssertEqual(keystore?.keystoreParams?.crypto.cipher, "aes-128-ctr") XCTAssertEqual(keystore?.keystoreParams?.crypto.kdf, "scrypt") XCTAssertEqual(keystore?.keystoreParams?.crypto.kdfparams.r, 8) XCTAssertEqual(keystore?.keystoreParams?.crypto.kdfparams.p, 1) XCTAssertEqual(keystore?.keystoreParams?.crypto.kdfparams.n, 1024) XCTAssertEqual(keystore?.keystoreParams?.crypto.kdfparams.dklen, 32) } func testDecodeKeystore() { let data = Data("abandon amount liar amount expire adjust cage candy arch gather drum buyer".utf8) let passwordData = Data("qwertyui".utf8) let keystore = try! KeystoreV3(data: data, passwordData: passwordData) guard let decoded = try? keystore?.getDecriptedKeyStore(passwordData: passwordData) else { fatalError() } XCTAssertEqual(decoded, data) } } ================================================ FILE: HDWalletKit_Tests/MnemonicTests.swift ================================================ // // MnemonicTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 12.07.18. // Copyright © 2018 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class MnemonicTests: XCTestCase { func testMenmonic() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) XCTAssertEqual( mnemonic, "abandon amount liar amount expire adjust cage candy arch gather drum buyer" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2) XCTAssertEqual( mnemonic2, "pen false anchor short side same crawl enhance luggage advice crisp village" ) } func testSeedGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "3779b041fab425e9c0fd55846b2a03e9a388fb12784067bd8ebdb464c2574a05bcc7a8eb54d7b2a2c8420ff60f630722ea5132d28605dbc996c8ca7d7a8311c0" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "2bb2ea75d2891584559506b2429426722bfa81958c824affb84b37def230fe94a7da1701d550fef6a216176de786150d0a4f2b7b3770139582c1c01a6958d91a" ) } func testJapaneceGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy, language: .japanese) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "8c62436b42e641181b155fcdb62af9dd960156b9ab6fbe58880174ce48a1d97fde3d43b622c2959fd437fd1ee1dcd96ccc4ca24dbd1317d770ac2bbfede5521f" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2, language: .japanese) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "e8d3649e4947e2200e6eb7057c511dea30521bc6194a9f79229a47f0a4e632204fab0a39f8cb6f43ba1321b0c089bb248c646c53ff8ff9fdbd08875158bf2977" ) } func testKoreanGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy, language: .korean) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "c84d23b603720bc67db1b1f5f1cbfc82b760736ad8069bf283c8d5d2a5b1e2075e73208fbe8763500b572839ff3c7827917a7d8eec19b2732152f84b0ace5b70" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2, language: .korean) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "a66483b021427983eb95a39af6ae13c256874b09ad32dd70f15221bdfedc39d9d012e9e788fdba47b31b06ab68a6373904b61e2438d0bd45d8db51496727ca56" ) } func testFrenchGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy, language: .french) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "b70232fad2698ee7236b5f789e1566157f41e9b0a22b4dfa0c3325172a6fd8513e0d552a12c335737275847d5b25a24bfaad97bdb4d98541901d3bd2a9cbfcf1" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2, language: .french) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "3b89dcaa78ace0ff67c74526697c5e67c327e5b2e2c5849b4348b2c39306cb3c8db8fbd3f6965aca7d2b65b16491d39a340b2c5800ab2ae06394c5d36e7dff9e" ) } func testItalianGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy, language: .italian) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "e26a889ebae217f1115abd8d324d850927af0af43b42ed4c333b8962e1088f8ee6a829628cdbb1c70a4fd691aa6adeb40e631fc8cb3aa44746c361ba34e8be21" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2, language: .italian) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "cff35bbe31ca088b224b7e16992cacb8a73431cdb32b2300f596a9570dba9642aada67c442851d7a7bbd1c62bb5924b7dd8d3cc76e7a4acc72e13b8899904981" ) } func testSimplifiedChineseGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy, language: .simplifiedChinese) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "9859899437d054276ba8301d0a27b0c0c67c6e2863d68ed8d52e44c5ed9e0cc4132a5f6ba37c4ee8a2f2bbc498293a642c9ff497fff1f5f546cae2c165e0f089" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2, language: .simplifiedChinese) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "6a3dd51b9ef724ebfed4372c6a64f766f615b3b8b5a2c39e9b623f51d2d099e9c7f8d131c842b54982a0b1cd20eb40fa25d266d9cad989c7dde8ffea7fc25155" ) } func testTraditionalChineseGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy, language: .traditionalChinese) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "3fac393cf2327d761e8443b66f2c5bb22cc59278c5b906b07dfd0f8be91e56c7bc60038744b2a8d89844f8746686c32fbb6a9e195b5e1fe811c60dc050e8654b" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2, language: .traditionalChinese) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "2198a94952b97a89f79bf5d62e59fdc5213b6e728b08065401ef2ea1bc6056a49cea4b505d4a92ecd5532b8bbaa9f08e7b7f9707b383a09eabbdb28f04f04d3e" ) } func testSpanishGeneration() { let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy, language: .spanish) let seed = Mnemonic.createSeed(mnemonic: mnemonic) XCTAssertEqual( seed.toHexString(), "21d369cf994a9b2d99c938c979d9ca95ceeb7ac55589622bf57e2f53e7edf7688eb32a140ac9206dbf219376a8ffc7ecf4d642a88834a1dfb633d75a34180b60" ) let entropy2 = Data(hex: "a26a4821e36c7f7dccaa5484c080cefa") let mnemonic2 = Mnemonic.create(entropy: entropy2, language: .spanish) let seed2 = Mnemonic.createSeed(mnemonic: mnemonic2) XCTAssertEqual( seed2.toHexString(), "f7f8c90b881e92fb3646e67a076006fa78c21320eeae3e034993468289eb7919f89140b0333e814d397fb0e42232cdb2dc3420016f4b5ed21dc5251630da8bf4" ) } } ================================================ FILE: HDWalletKit_Tests/PrivateKeyTests.swift ================================================ // // PrivateKeyTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 4/18/19. // Copyright © 2019 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class PrivateKeyTests: XCTestCase { func testBitcoin() { let address = "1MVEQHYUv1bWiYJB77NNEEEdbmNFEoW5q6" let rawPk = "0e66055a963cc3aecb185cf795de476cf290c88db671297da041b7f7377e6f9c" let hexPk = "0e66055a963cc3aecb185cf795de476cf290c88db671297da041b7f7377e6f9c" let uncompressedPk = "5HvdNYs1baLY7vpnmb2osg5gZHvAFxDiBoCujs2vfTjC442rzSK" let compressedPk = "KwhhY7djdc9EMaZw1oCytfVfbXfdrzj6newZnBqVrkyDnKVWiCmJ" [hexPk, compressedPk, uncompressedPk].forEach { testImportFromPK(coin: .bitcoin, privateKey: $0, address: address, raw: rawPk) } } func testBitcoinCash() { let address = "1MVEQHYUv1bWiYJB77NNEEEdbmNFEoW5q6" let rawPk = "0e66055a963cc3aecb185cf795de476cf290c88db671297da041b7f7377e6f9c" let hexPk = "0e66055a963cc3aecb185cf795de476cf290c88db671297da041b7f7377e6f9c" let uncompressedPk = "5HvdNYs1baLY7vpnmb2osg5gZHvAFxDiBoCujs2vfTjC442rzSK" let compressedPk = "KwhhY7djdc9EMaZw1oCytfVfbXfdrzj6newZnBqVrkyDnKVWiCmJ" [hexPk, uncompressedPk, compressedPk].forEach { testImportFromPK(coin: .bitcoinCash, privateKey: $0, address: address, raw: rawPk) } } func testDogecoin() { let address = "DHhBBVF46Wzc8pR6swZD9GoDdX8x7MDgvw" let rawPk = "0e66055a963cc3aecb185cf795de476cf290c88db671297da041b7f7377e6f9c" let hexPk = "0e66055a963cc3aecb185cf795de476cf290c88db671297da041b7f7377e6f9c" let uncompressedPk = "6KetuZozmLRbBFKM474EcBNFo5w6zuRRWM661hjFZzobJoLuNCh" let compressedPk = "KwhhY7djdc9EMaZw1oCytfVfbXfdrzj6newZnBqVrkyDnKVWiCmJ" [hexPk, uncompressedPk, compressedPk].forEach { testImportFromPK(coin: .bitcoinCash, privateKey: $0, address: address, raw: rawPk) } } func testLitecoin() { let address = "Lbre6AY3tc8X2GJ2tKERVvcCA4S2EzF6wJ" let rawPk = "857cfceb9726ba7165fdcda93c056d35a8ba9b90a8c77fac524a309d832de107" let hexPk = "857cfceb9726ba7165fdcda93c056d35a8ba9b90a8c77fac524a309d832de107" let uncompressedPk = "6v8opvTbpSE2WwTv4rhEvSVK1jqGTXKRkWk484gxmc4TtQzDu53" let compressedPk = "T7XTgWxQgNLVh9PoE2LcSsVxWG43E4pLF4H2nBHP9skHfjshodfM" [hexPk, uncompressedPk, compressedPk].forEach { testImportFromPK(coin: .litecoin, privateKey: $0, address: address, raw: rawPk) } } func testImportFromPK(coin: Coin, privateKey: String, address: String, raw: String) { let pk = PrivateKey(pk: privateKey, coin: coin) XCTAssertEqual(pk!.publicKey.address, address) XCTAssertEqual(pk?.raw, Data(hex: raw)) } } ================================================ FILE: HDWalletKit_Tests/RIPEMD160Tests.swift ================================================ // // RIPEMD160Tests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 4/23/19. // Copyright © 2019 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class RIPEMD160Tests: XCTestCase { func testEncode() { let data = Data("Essentia".utf8) let encodedData = Data(hex: "f70feccc344d80f6fc07ad29292c8ab3cf6753d7") let ripemd = RIPEMD160.hash(data) XCTAssertEqual(ripemd, encodedData) } } ================================================ FILE: HDWalletKit_Tests/Secp256k1Tets.swift ================================================ // // Secp256k1Tets.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 4/23/19. // Copyright © 2019 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class Secp256k1Tets: XCTestCase { func testEncode() { } } ================================================ FILE: HDWalletKit_Tests/SignTransactionTests.swift ================================================ // // SignTransactionTests.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 20.09.18. // Copyright © 2018 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class SignTransactionTests: XCTestCase { func testSign() { let transaction = EthereumRawTransaction(value: 0x00, to: "0x0000000000000000000000000000000000000000", gasPrice: 0x09184e72a000, gasLimit: 0x2710, nonce: 0x00, data: Data(hex: "0x7f7465737432000000000000000000000000000000000000000000000000000000600057")) let pk = Data(hex: "e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109") let data = try! EIP155Signer(chainId: 1).sign(transaction, privateKey: pk); XCTAssertEqual("0xf889808609184e72a00082271094000000000000000000000000000000000000000080a47f746573743200000000000000000000000000000000000000000000000000000060005726a0e334b3350ecadf15dfe6ac58c75b386e6b5e6ef997589e62368c7c74777abd67a00ace9b8c332799dd54da03c8a44c3191b456b2f067ad575d4022d3a81e9318c7", data.toHexString().addHexPrefix()) } func testSign1() { let transaction = EthereumRawTransaction(value: Wei("1000000000000000000")!, to: "0x91c79f31De5208fadCbF83f0a7B0A9b6d8aBA90F", gasPrice: 99000000000, gasLimit: 21000, nonce: 0) let pk = Data(hex: "db173e58671248b48d2494b63a99008be473268581ca1eb78ed0b92e03b13bbc") let data = try! EIP155Signer(chainId: 1).sign(transaction, privateKey: pk); XCTAssertEqual("0xf86c8085170cdc1e008252089491c79f31de5208fadcbf83f0a7b0a9b6d8aba90f880de0b6b3a76400008025a0f62b35ed65db13b02ccab29eeea2d29990a690a8620f8bee56b765c5357c82b8a05c266f2d429c87f8c903f7089870aa169638518c5c3a56ade8ce66ffcb5c3991", data.toHexString().addHexPrefix()) } func testBitcoinSign() { let pk = PrivateKey(pk: "L5GgBH1U8PuNuzCQGvvEH3udEXCEuJaiK96e88romhpGa1cU7JTY", coin: .bitcoin)! let lockingScript: Data = Data(hex: "76a914e42a54ba2042e889461c7966ac6ba13eeb144a3f88ac") let txidData: Data = Data(hex: "9ced8296cf15e67295a99aa0389229e27eae571436925db587665ba02210bcf3") let txHash: Data = Data(txidData.reversed()) let output = TransactionOutput(value: 524839, lockingScript: lockingScript) let outpoint = TransactionOutPoint(hash: txHash, index: 352337565) let utxo = UnspentTransaction(output: output, outpoint: outpoint) let address = try! LegacyAddress("1HLqrFX5fYwKriU7LRKMQGhwpz5HuszjnK", coin: .bitcoin) let utxoWallet = UTXOWallet(privateKey: pk) do { let signedTx = try utxoWallet.createTransaction(to: address, amount: 0, utxos: [utxo]) XCTAssertEqual(signedTx, "01000000000200000000000000001976a914b342b16a24dffc3be74ccf202e418fc22c271cbd88ac00000000000000001976a9144f5cd7cf2e4d0ec1bcbd82b64691e2f7867b618688ac00000000") } catch { print(error) } } } ================================================ FILE: HDWalletKit_Tests/UTXO/UTXOSign.swift ================================================ // // UTXOSign.swift // HDWalletKit_Tests // // Created by Pavlo Boiko on 3/26/19. // Copyright © 2019 Essentia. All rights reserved. // import XCTest @testable import HDWalletKit class UTXOSign: XCTestCase { func testBitcoinSign() { let pk = PrivateKey(pk: "L5GgBH1U8PuNuzCQGvvEH3udEXCEuJaiK96e88romhpGa1cU7JTY", coin: .bitcoin)! let lockingScript: Data = Data(hex: "76a914e42a54ba2042e889461c7966ac6ba13eeb144a3f88ac") let txidData: Data = Data(hex: "9ced8296cf15e67295a99aa0389229e27eae571436925db587665ba02210bcf3") let txHash: Data = Data(txidData.reversed()) let output = TransactionOutput(value: 524839, lockingScript: lockingScript) let outpoint = TransactionOutPoint(hash: txHash, index: 352337565) let utxo = UnspentTransaction(output: output, outpoint: outpoint) let address = try! LegacyAddress("1HLqrFX5fYwKriU7LRKMQGhwpz5HuszjnK", coin: .bitcoin) let utxoWallet = UTXOWallet(privateKey: pk) do { let signedTx = try utxoWallet.createTransaction(to: address, amount: 10000, utxos: [utxo]) XCTAssertEqual(signedTx, "0100000001f3bc1022a05b6687b55d92361457ae7ee2299238a09aa99572e615cf9682ed9c9d3e00156b483045022100e1283f8ac9d00d4a393f5629db9df867a1702da309a9125746f2a332c21038d20220015baf4d864254f47f08140853dd58b78f9df1749ff0e2b81ac5a9f6345b987e01210346a4129884b46fdb7f7977c6e90ed4c367af343494f3ff5272db721752d28ef3ffffffff0210270000000000001976a914b342b16a24dffc3be74ccf202e418fc22c271cbd88ac35da0700000000001976a9144f5cd7cf2e4d0ec1bcbd82b64691e2f7867b618688ac00000000") } catch { print(error) } } func testBitcoinCashSign() { let pk = PrivateKey(pk: "KwgDcj2ZDN5vzRXsTv1F6vzQV7nx7shEYjFBcWng1sH6Fy9rhK2b", coin: .bitcoinCash)! let lockingScript: Data = Data(hex: "76a914e42a54ba2042e889461c7966ac6ba13eeb144a3f88ac") let txidData: Data = Data(hex: "9ced8296cf15e67295a99aa0389229e27eae571436925db587665ba02210bcf3") let txHash: Data = Data(txidData.reversed()) let output = TransactionOutput(value: 524839, lockingScript: lockingScript) let outpoint = TransactionOutPoint(hash: txHash, index: 352337565) let utxo = UnspentTransaction(output: output, outpoint: outpoint) let address = try! LegacyAddress("1HLqrFX5fYwKriU7LRKMQGhwpz5HuszjnK", coin: .bitcoinCash) let utxoWallet = UTXOWallet(privateKey: pk) do { let signedTx = try utxoWallet.createTransaction(to: address, amount: 10000, utxos: [utxo]) XCTAssertEqual(signedTx, "0100000001f3bc1022a05b6687b55d92361457ae7ee2299238a09aa99572e615cf9682ed9c9d3e00156a473044022013373441cc4521f4c4d89b454520ebedaebe4e035b5e1f9575886f1eaad4e91302200af1062f4c4e8c0633b9e3570f1d399af3f04d5ca5806bb9d62a162dfba9a2b64121030f6c58f37ffe1bf56dd79fac07f339f44d96efaa3d78e1f32fadd41dcd0b7bbcffffffff0210270000000000001976a914b342b16a24dffc3be74ccf202e418fc22c271cbd88ac35da0700000000001976a9149f902c3c088cc352eae162bcb8fb0540b47c971188ac00000000") } catch { print(error) } } func testDashSign() { let pk = PrivateKey(pk: "XJpB8Kdaws3YzzS4dfLBhoUmyrzMkVp3KxKg1deiHk9dnLwZYPcA", coin: .dash)! let lockingScript: Data = Data(hex: "76a914e42a54ba2042e889461c7966ac6ba13eeb144a3f88ac") let txidData: Data = Data(hex: "9ced8296cf15e67295a99aa0389229e27eae571436925db587665ba02210bcf3") let txHash: Data = Data(txidData.reversed()) let output = TransactionOutput(value: 524839, lockingScript: lockingScript) let outpoint = TransactionOutPoint(hash: txHash, index: 352337565) let utxo = UnspentTransaction(output: output, outpoint: outpoint) let address = try! LegacyAddress("Xud1fZjupDuhndpYtTquDPmSWmehtEbxhy", coin: .dash) let utxoWallet = UTXOWallet(privateKey: pk) do { let signedTx = try utxoWallet.createTransaction(to: address, amount: 10000, utxos: [utxo]) XCTAssertEqual(signedTx, "0100000001f3bc1022a05b6687b55d92361457ae7ee2299238a09aa99572e615cf9682ed9c9d3e00156a47304402202a7aaddeb07faf748ef48ffeccb0c61ee87840a468ead1dd8e4b6aa9003527470220143f1c6429662da1f0906b43bda82d1fa8c76711256502c1d08b8f9be43a42270121035d72ea3bae4502aadb86a7ab678004585ab9b27e12bbf01d13f514f9159f8adfffffffff0210270000000000001976a914cfb0ef26fa554125f6dbae9762f9b914bc823bc388ac35da0700000000001976a914553869406141a4145ed9050737266c4a4790b2b088ac00000000") } catch { print(error) } } func testRawTransactionCration() { let pk = PrivateKey(pk: "L5VqJYoBWVKwe3icNjSGz5maPmAaSm32TEjPdxMNyix8groNubU8", coin: .bitcoin)! print(pk.publicKey.address) } } ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2018 Pavlo Boiko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Podfile ================================================ platform :ios, '11.0' target 'HDWalletKit' do use_frameworks! pod 'secp256k1.swift', '~> 0.1.4' pod 'CryptoSwift', '~> 1.0.0' target 'HDWalletKit_Tests' do pod 'CryptoSwift', '~> 1.0.0' pod 'secp256k1.swift', '~> 0.1.4' end end ================================================ FILE: README.md ================================================ [![Build Status](https://travis-ci.com/essentiaone/HDWallet.svg?branch=develop)](https://travis-ci.com/essentiaone/HDWallet) [![Black Duck Security Risk](https://copilot.blackducksoftware.com/github/repos/essentiaone/HDWallet/branches/develop/badge-risk.svg)](https://copilot.blackducksoftware.com/github/repos/essentiaone/HDWallet/branches/develop) [![Badge w/ Version](https://cocoapod-badges.herokuapp.com/v/HDWalletKit/badge.png)](https://cocoadocs.org/docsets/HDWalletKit) [![Badge w/ Platform](https://cocoapod-badges.herokuapp.com/p/HDWalletKit/badge.svg)](https://cocoadocs.org/docsets/HDWalletKit) [![Badge w/ Licence](https://cocoapod-badges.herokuapp.com/l/HDWalletKit/badge.svg)](https://cocoadocs.org/docsets/HDWalletKit) # HDWalletKit HDWalletKit is a Swift framwork that enables you to create and use bitcoin HD wallet ([Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)) in your own app.

You can check if the address generation is working right [here](https://iancoleman.io/bip39/). ## Features - HD and NonHD wallets support - Mnemonic recovery phrease in [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) - Keystore generation - Read keystore file - Sign ether transaction - ERC20 Tokens - Sign UTXO based transaction ## Installation ### CocoaPods

To integrate HDWalletKit into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'HDWalletKit'
### Carthage To install with [Carthage](https://github.com/Carthage/Carthage), simply add this in your `Cartfile`: ```ruby github "essentiaone/HDWallet" ``` ## Communication - If you **found a bug**, open an issue. - If you **have a feature request**, open an issue. - If you **want to contribute**, submit a pull request. ## How to use #### Generate seed and convert it to mnemonic sentence. ```swift let entropy = Data(hex: "000102030405060708090a0b0c0d0e0f") let mnemonic = Mnemonic.create(entropy: entropy) print(mnemonic) // abandon amount liar amount expire adjust cage candy arch gather drum buyer let seed = Mnemonic.createSeed(mnemonic: mnemonic) print(seed.toHexString()) ``` #### PrivateKey and key derivation (BIP39) ```swift let mnemonic = Mnemonic.create() let seed = Mnemonic.createSeed(mnemonic: mnemonic) let privateKey = PrivateKey(seed: seed, coin: .bitcoin) // BIP44 key derivation // m/44' let purpose = privateKey.derived(at: .hardened(44)) // m/44'/0' let coinType = purpose.derived(at: .hardened(0)) // m/44'/0'/0' let account = coinType.derived(at: .hardened(0)) // m/44'/0'/0'/0 let change = account.derived(at: .notHardened(0)) // m/44'/0'/0'/0/0 let firstPrivateKey = change.derived(at: .notHardened(0)) print(firstPrivateKey.publicKey.address) ``` #### Generate keystore file ```swift let data = "abandon amount liar amount expire adjust cage candy arch gather drum buyer" let keystore = try! KeystoreV3(data: data, password: "qwertyui") let encodedKeystoreDaya = (try? keystore?.encodedData()) ``` #### Open keystore file ```swift let keystore = try! KeystoreV3(data: encodedKeystoreDaya, password: password) guard let decoded = try? keystore?.getDecriptedKeyStore(password: password) else { fatalError() } print(decoded) ``` #### Create your wallet and generate address ```swift let mnemonic = Mnemonic.create() let seed = Mnemonic.createSeed(mnemonic: mnemonic) let network: Network = .main(.bitcoin) let wallet = Wallet(seed: seed, network: network) let account = wallet.generateAccount() print(account) ``` #### Sign Ethereum transaction by private key ```swift let signer = EIP155Signer() let rawTransaction1 = EthereumRawTransaction( value: Wei("10000000000000000")!, to: "0x34205555576717bBdF8158E2b2c9ed64EB1e6B85", gasPrice: 99000000000, gasLimit: 21000, nonce: 2 ) guard let signed = try? signer.hash(rawTransaction: rawTransaction1).toHexString() else { return } print(signed) ``` #### Sign Bitcoin transaction by private key For getting UTXO you can use (https://github.com/essentiaone/essentia-bridges-api-ios) ```swift let address = try LegacyAddress("1HLqrFX5fYwKriU7LRKMQGhwpz5HuszjnK", coin: .bitcoin) let utxoWallet = UTXOWallet(privateKey: "Kz9UKkL6bKE92QPxQbPcqkCZTnCyLVyfRNFRSbToNjyb4bx321fh") let signedTx = try utxoWallet.createTransaction(to: address, amount: 0, utxos: utxos) ``` #### Create send ERC20 tokens transaction data ```swift let erc20Token = ERC20(contractAddress: "0x8f0921f30555624143d427b340b1156914882c10", decimal: 18, symbol: "ESS") let address = "0x2f5059f64D5C0c4895092D26CDDacC58751e0C3C" let data = try! erc20Token.generateDataParameter(toAddress: address, amount: "3") ``` #### Create get balance ERC20 token transaction data ```swift let erc20Token = ERC20(contractAddress: "0x8f0921f30555624143d427b340b1156914882c10", decimal: 18, symbol: "ESS") let data = try! erc20Token.generateGetBalanceParameter(toAddress: "2f5059f64D5C0c4895092D26CDDacC58751e0C3C") ``` #### Convert non HD PrivateKey to Address ```swift let privateKey = PrivateKey(pk: "L35qaFLpbCc9yCzeTuWJg4qWnTs9BaLr5CDYcnJ5UnGmgLo8JBgk", coin: .bitcoin) print(privateKey.publicKey.address) //128BCBZndgrPXzEgF4QbVR3jnQGwzRtEz5 ``` ## License WalletKit is released under the [MIT License](https://github.com/essentiaone/HDWallet/blob/develop/LICENSE.md). ================================================ FILE: scripts/coverage.rb ================================================ project_name = ARGV[0] profdata = Dir.glob(File.join('build', '/**/Coverage.profdata')).first Dir.glob(File.join('build', "/**/#{project_name}")) do |target| output = `xcrun llvm-cov report -instr-profile "#{profdata}" "#{target}" -arch=x86_64` if $?.success? puts output `xcrun llvm-cov show -instr-profile "#{profdata}" "#{target}" -arch=x86_64 -use-color=0 > coverage.txt` break end end