diff --git a/Sources/TorusUtils/Extensions/TorusUtils+extension.swift b/Sources/TorusUtils/Extensions/TorusUtils+extension.swift index a6526d55..989ccbe2 100644 --- a/Sources/TorusUtils/Extensions/TorusUtils+extension.swift +++ b/Sources/TorusUtils/Extensions/TorusUtils+extension.swift @@ -178,7 +178,7 @@ extension TorusUtils { private func getShareOrKeyAssign(endpoints: [String], nodeSigs: [CommitmentRequestResponse], verifier: String, verifierParams: VerifierParams, idToken: String, extraParams: [String: Any] = [:]) async throws -> [URLRequest] { let session = createURLSession() - let threshold = Int(endpoints.count / 2) + 1 + let threshold = Int(endpoints.count / 2) + 1 var rpcdata: Data = Data() let loadedStrings = extraParams @@ -230,6 +230,40 @@ extension TorusUtils { + private func reconstructKey(decryptedShares: [Int: String], thresholdPublicKey: KeyAssignment.PublicKey) throws -> String? { + + // run lagrange interpolation on all subsets, faster in the optimistic scenario than berlekamp-welch due to early exit + let allCombis = kCombinations(s: decryptedShares.count, k: 3) + var returnedKey: String? = nil + + for j in 0.. String { + internal func decryptNodeData(eciesData: EciesHex, ciphertextHex: String, privKey: String, padding: Padding = .pkcs7) throws -> String { let eciesOpts = ECIES( iv: eciesData.iv, @@ -731,7 +767,7 @@ extension TorusUtils { mac: eciesData.mac ) - let decryptedSigBuffer = try decrypt(privateKey: privKey, opts: eciesOpts).toHexString() + let decryptedSigBuffer = try decrypt(privateKey: privKey, opts: eciesOpts, padding: padding).toHexString() return decryptedSigBuffer } @@ -834,8 +870,8 @@ extension TorusUtils { do { // AES-CBCblock-256 let aes = try AES(key: AesEncryptionKey.hexa, blockMode: CBC(iv: iv), padding: .pkcs7) - let decrypt = try aes.decrypt(share) - result[nodeIndex] = decrypt.hexa + let decryptData = try aes.decrypt(share) + result[nodeIndex] = decryptData.hexa } catch let err { result[nodeIndex] = TorusUtilError.decodingFailed(err.localizedDescription).debugDescription } @@ -884,8 +920,7 @@ extension TorusUtils { // Convert shares to BigInt(Shares) var shareList = [BigInt: BigInt]() - _ = shares.map { shareList[BigInt($0.key + offset)] = BigInt($0.value, radix: 16) } - os_log("lagrangeInterpolation: %@ %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, shares, shareList) + _ = shares.map { shareList[BigInt($0.key + offset)] = BigInt($0.value.addLeading0sForLength64(), radix: 16) } var secret = BigUInt("0") // to support BigInt 4.0 dependency on cocoapods var sharesDecrypt = 0 @@ -1513,7 +1548,7 @@ extension TorusUtils { return tupleElements } - public func decrypt(privateKey: String, opts: ECIES) throws -> Data { + public func decrypt(privateKey: String, opts: ECIES, padding: Padding = .pkcs7) throws -> Data { let ephermalPublicKey = opts.ephemPublicKey.strip04Prefix() let ephermalPublicKeyBytes = ephermalPublicKey.hexa var ephermOne = ephermalPublicKeyBytes.prefix(32) @@ -1538,9 +1573,9 @@ extension TorusUtils { let aesEncryptionKey = hash.prefix(64) do { // AES-CBCblock-256 - let aes = try AES(key: aesEncryptionKey.hexa, blockMode: CBC(iv: iv), padding: .pkcs7) - let decrypt = try aes.decrypt(opts.ciphertext.hexa) - let data = Data(decrypt) + let aes = try AES(key: aesEncryptionKey.hexa, blockMode: CBC(iv: iv), padding: padding) + let decryptData = try aes.decrypt(opts.ciphertext.hexa) + let data = Data(decryptData) return data diff --git a/Sources/TorusUtils/Interfaces/ShareRequestResult.swift b/Sources/TorusUtils/Interfaces/ShareRequestResult.swift index eed40d78..41e0d79b 100644 --- a/Sources/TorusUtils/Interfaces/ShareRequestResult.swift +++ b/Sources/TorusUtils/Interfaces/ShareRequestResult.swift @@ -8,6 +8,7 @@ struct ShareRequestResult : Decodable { let sessionTokenSigMetadata: [EciesHex] let nodePubX: String let nodePubY: String + let isNewKey: String enum CodingKeys: CodingKey { case keys @@ -17,6 +18,7 @@ struct ShareRequestResult : Decodable { case session_token_sig_metadata case node_pubx case node_puby + case is_new_key } init(from decoder: Decoder) throws { @@ -24,7 +26,8 @@ struct ShareRequestResult : Decodable { self.keys = try container.decode([KeyAssignment].self, forKey: .keys) self.nodePubX = try container.decode(String.self, forKey: .node_pubx) self.nodePubY = try container.decode(String.self, forKey: .node_puby) - + self.isNewKey = try container.decode(String.self, forKey: .is_new_key) + if let sessionTokens = try? container.decodeIfPresent([String].self, forKey: .session_tokens) { self.sessionTokens = sessionTokens } else { @@ -48,6 +51,7 @@ struct ShareRequestResult : Decodable { } else { self.sessionTokenSigMetadata = [] } + } // public func encode(to encoder: Encoder) throws { diff --git a/Sources/TorusUtils/TorusUtils.swift b/Sources/TorusUtils/TorusUtils.swift index 954c3cb2..aa29bdae 100644 --- a/Sources/TorusUtils/TorusUtils.swift +++ b/Sources/TorusUtils/TorusUtils.swift @@ -55,10 +55,9 @@ open class TorusUtils: AbstractTorusUtils { // MARK: - getPublicAddress public func getPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, extendedVerifierId :String? = nil ) async throws -> TorusPublicKey { - switch network { - case .legacy(_) : + if (self.isLegacyNetwork()) { return try await getLegacyPublicAddress(endpoints: endpoints, torusNodePubs: torusNodePubs , verifier: verifier, verifierId: verifierId, enableOneKey: self.enableOneKey) - case .sapphire(_) : + } else { return try await getNewPublicAddress(endpoints: endpoints, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId, enableOneKey: self.enableOneKey) } } @@ -74,11 +73,10 @@ open class TorusUtils: AbstractTorusUtils { extraParams: [String:Codable] = [:] ) async throws -> TorusKey { - switch network { - case .legacy(_) : + if (self.isLegacyNetwork()) { let result = try await legacyRetrieveShares(torusNodePubs: torusNodePubs, indexes: indexes, endpoints: endpoints, verifier: verifier, verifierId: verifierParams.verifier_id, idToken: idToken, extraParams: extraParams) return result - case .sapphire(_) : + } else { let result = try await retrieveShare( legacyMetadataHost: self.legacyMetadataHost, @@ -101,14 +99,14 @@ open class TorusUtils: AbstractTorusUtils { public func getUserTypeAndAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, extendedVerifierId :String? = nil) async throws -> TorusPublicKey { - switch network { - case .legacy(_) : + if (self.isLegacyNetwork()) { return try await getLegacyPublicAddress(endpoints: endpoints, torusNodePubs: torusNodePubs, verifier: verifier, verifierId: verifierId, enableOneKey: true) - case .sapphire(_) : + } + else { return try await getNewPublicAddress(endpoints: endpoints, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId, enableOneKey: true) } - } + } private func getNewPublicAddress(endpoints: [String], verifier: String, verifierId: String, extendedVerifierId :String? = nil, enableOneKey: Bool) async throws -> TorusPublicKey { @@ -431,8 +429,8 @@ open class TorusUtils: AbstractTorusUtils { throw TorusUtilError.decodingFailed(decoded.error?.data) } os_log("retrieveDecryptAndReconstuct: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .info), type: .info, "\(decoded)") - var X = lookupPubkeyX - var Y = lookupPubkeyY + var X = lookupPubkeyX.addLeading0sForLength64() + var Y = lookupPubkeyY.addLeading0sForLength64() if let decodedResult = decoded.result as? LegacyLookupResponse { // case non migration let keyObj = decodedResult.keys @@ -477,7 +475,7 @@ open class TorusUtils: AbstractTorusUtils { if filteredData.count < threshold { throw TorusUtilError.thresholdError } - let thresholdLagrangeInterpolationData = try thresholdLagrangeInterpolation(data: filteredData, endpoints: endpoints, lookupPubkeyX: X, lookupPubkeyY: Y) + let thresholdLagrangeInterpolationData = try thresholdLagrangeInterpolation(data: filteredData, endpoints: endpoints, lookupPubkeyX: X.addLeading0sForLength64(), lookupPubkeyY: Y.addLeading0sForLength64()) session.invalidateAndCancel() return thresholdLagrangeInterpolationData case .failure(let error): diff --git a/Tests/TorusUtilsTests/SapphireTest.swift b/Tests/TorusUtilsTests/SapphireTest.swift index 279c5eb0..ab32083c 100644 --- a/Tests/TorusUtilsTests/SapphireTest.swift +++ b/Tests/TorusUtilsTests/SapphireTest.swift @@ -174,6 +174,54 @@ final class SapphireTest: XCTestCase { } + + func testNewUserLogin() async throws { + let exp1 = XCTestExpectation(description: "Should be able to do a Login") + + let fakeEmail = generateRandomEmail(of: 6) + let verifierId = fakeEmail //faker random address + let token = try generateIdToken(email: verifierId) + + let verifierParams = VerifierParams(verifier_id: verifierId) + + do { + let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: verifierId) + + let data = try await torus.retrieveShares( + endpoints: nodeDetails.getTorusNodeEndpoints(), + torusNodePubs: nodeDetails.getTorusNodePub(), + indexes: nodeDetails.getTorusIndexes(), + verifier: TORUS_TEST_VERIFIER, + verifierParams: verifierParams, + idToken: token + ) + + XCTAssertEqual(data.metadata?.typeOfUser, .v2) + XCTAssertEqual(data.metadata?.upgraded, false) + XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.finalKeyData?.X, "") + XCTAssertNotEqual(data.finalKeyData?.Y, "") + XCTAssertNotEqual(data.finalKeyData?.privKey, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.X, "") + XCTAssertNotEqual(data.oAuthKeyData?.Y, "") + XCTAssertNotEqual(data.oAuthKeyData?.privKey, "") + XCTAssertNotEqual(data.sessionData?.sessionTokenData.count, 0) + XCTAssertNotEqual(data.sessionData?.sessionAuthKey, "") + XCTAssertNotEqual(data.metadata?.pubNonce?.x, "") + XCTAssertNotEqual(data.metadata?.pubNonce?.y, "") + XCTAssertNotEqual(data.nodesData?.nodeIndexes.count, 0) + + exp1.fulfill() + } catch let error{ + XCTFail(error.localizedDescription) + exp1.fulfill() + } + + + } + + func testNodeDownAbleToLogin () async throws { let exp1 = XCTestExpectation(description: "should be able to login even when node is down") @@ -369,6 +417,7 @@ final class SapphireTest: XCTestCase { let exp1 = XCTestExpectation(description: "Should be able to aggregate login") let email = generateRandomEmail(of: 6) + print("email", email) let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER let verifierID: String = email let jwt = try! generateIdToken(email: email) @@ -381,7 +430,7 @@ final class SapphireTest: XCTestCase { let verifierParams = VerifierParams(verifier_id: verifierID) do { let nodeDetails = try await get_fnd_and_tu_data(verifer: verifier, veriferID: verifierID) - + let data = try await torus.retrieveShares(endpoints: endpoint.torusNodeEndpoints, torusNodePubs: nodeDetails.getTorusNodePub(),indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken, extraParams: extraParams) XCTAssertNotNil(data.finalKeyData?.evmAddress) @@ -390,6 +439,7 @@ final class SapphireTest: XCTestCase { XCTAssertEqual(data.metadata?.typeOfUser, .v2) XCTAssertNotNil(data.metadata?.nonce) XCTAssertEqual(data.metadata?.upgraded, false) + exp1.fulfill() } catch let err { XCTFail(err.localizedDescription)