diff --git a/Package.resolved b/Package.resolved index 0338e0f4..a6e29bdc 100644 --- a/Package.resolved +++ b/Package.resolved @@ -32,8 +32,8 @@ "package": "curvelib.swift", "repositoryURL": "https://github.com/tkey/curvelib.swift", "state": { - "branch": "refactor", - "revision": "3477abff071170d005f05397c6049478fa6ecaf3", + "branch": "extension", + "revision": "d5acae05bfd832393524ec8e0bf8820a745e5331", "version": null } }, diff --git a/Package.swift b/Package.swift index 108b8673..f51e29f2 100644 --- a/Package.swift +++ b/Package.swift @@ -11,7 +11,7 @@ let package = Package( targets: ["TorusUtils"]) ], dependencies: [ - .package(name: "curvelib.swift", url: "https://github.com/tkey/curvelib.swift", .branch("refactor")), + .package(name: "curvelib.swift", url: "https://github.com/tkey/curvelib.swift", .branch("extension")), .package(name:"FetchNodeDetails", url: "https://github.com/torusresearch/fetch-node-details-swift", from: "5.1.0"), .package(name:"CryptoSwift", url: "https://github.com/krzyzanowskim/CryptoSwift",from: "1.5.1"), .package(name:"jwt-kit", url: "https://github.com/vapor/jwt-kit", from: "4.0.0"), diff --git a/Sources/TorusUtils/Extensions/CurveSecp256k1+Extension.swift b/Sources/TorusUtils/Extensions/CurveSecp256k1+Extension.swift deleted file mode 100644 index 663d8404..00000000 --- a/Sources/TorusUtils/Extensions/CurveSecp256k1+Extension.swift +++ /dev/null @@ -1,109 +0,0 @@ -import Foundation -#if canImport(curvelib_swift) - import curvelib_swift -#endif - -public struct CurveSecp256k1 {} - -extension CurveSecp256k1 { - public static func ecdh(publicKey: PublicKey, privateKey: SecretKey) throws -> [UInt8] { - let shared = try publicKey.mul(key: privateKey) - let serialized = try shared.serialize(compressed: true) - let data = Data(hex: serialized).dropFirst() - return data.bytes.sha512() - } - - public static func ecdhWithHex(pubKeyHex: String, privateKeyHex: String) throws -> [UInt8] { - - let sharedSecret = try ecdh(publicKey: PublicKey(hex: pubKeyHex), privateKey: SecretKey(hex: privateKeyHex)) - return sharedSecret - } - - public static func privateToPublic(privateKey: SecretKey, compressed: Bool = false) throws -> String { - let publicKey = try privateKey.to_public() - return try publicKey.serialize(compressed: compressed) - } - - private static func constantTimeComparison(_ lhs: Data, _ rhs: Data) -> Bool { - guard lhs.count == rhs.count else { return false } - var difference = UInt8(0x00) - for i in 0 ..< lhs.count { // compare full length - difference |= lhs[i] ^ rhs[i] // constant time - } - return difference == UInt8(0x00) - } - - private static func toByteArray(_ value: T) -> [UInt8] { - var value = value - return withUnsafeBytes(of: &value) { Array($0) } - } - - public static func verifyPrivateKey(privateKey: String) -> Bool { - do { - _ = try SecretKey(hex: privateKey) - return true; - } catch (_) { - return false; - } - } - - public static func recoverPublicKey(hash: String, signature: String, compressed: Bool = false) throws -> String { - let sig = try Signature(hex: signature) - debugPrint(try sig.serialize()) - return try ECDSA.recover(signature: sig, hash: hash).serialize(compressed: compressed) - } - - public static func parseSignature(signature: String) throws -> curvelib_swift.Signature { - return try Signature(hex: signature) - } - - internal static func serializeSignature(recoverableSignature: curvelib_swift.Signature) throws -> String { - return try recoverableSignature.serialize() - } - - internal static func recoverPublicKey(hash: String, recoverableSignature: curvelib_swift.Signature) throws -> PublicKey { - return try ECDSA.recover(signature: recoverableSignature, hash: hash) - } - - private static func randomBytes(length: Int) -> Data? { - for _ in 0 ... 1024 { - var data = Data(repeating: 0, count: length) - let result = data.withUnsafeMutableBytes { mutableRBBytes -> Int32? in - if let mutableRBytes = mutableRBBytes.baseAddress, mutableRBBytes.count > 0 { - let mutableBytes = mutableRBytes.assumingMemoryBound(to: UInt8.self) - return SecRandomCopyBytes(kSecRandomDefault, 32, mutableBytes) - } else { - return nil - } - } - if let res = result, res == errSecSuccess { - return data - } else { - continue - } - } - return nil - } - - internal static func recoverableSign(hash: String, privateKey: String) throws -> curvelib_swift.Signature { - let sk = try SecretKey(hex: privateKey) - return try ECDSA.sign_recoverable(key: sk, hash: hash) - } - - public static func signForRecovery(hash: String, privateKey: SecretKey) throws -> curvelib_swift.Signature { - return try ECDSA.sign_recoverable(key: privateKey, hash: hash) - } - - static func parsePublicKey(serializedKey: String) throws -> PublicKey { - return try PublicKey(hex: serializedKey) - } - - public static func serializePublicKey(publicKey: PublicKey, compressed: Bool = false) throws -> String { - return try publicKey.serialize(compressed: compressed) - } - - public static func combineSerializedPublicKeys(keys: PublicKeyCollection, outputCompressed: Bool = false) throws -> String { - let combined = try PublicKey.combine(collection: keys) - return try combined.serialize(compressed: outputCompressed) - } -} diff --git a/Sources/TorusUtils/Extensions/TorusUtils+extension.swift b/Sources/TorusUtils/Extensions/TorusUtils+extension.swift index 2505c81d..619433b3 100644 --- a/Sources/TorusUtils/Extensions/TorusUtils+extension.swift +++ b/Sources/TorusUtils/Extensions/TorusUtils+extension.swift @@ -13,6 +13,12 @@ import OSLog extension TorusUtils { // MARK: - utils + internal func ecdh_sha512(publicKey: PublicKey, privateKey: SecretKey) throws -> [UInt8] { + let shared = try ECDH.ecdhStandard(sk: privateKey, pk: publicKey) + let data = Data(hex: shared).dropFirst() + return data.bytes.sha512() + } + internal func combinations(elements: ArraySlice, k: Int) -> [[T]] { if k == 0 { return [[]] @@ -120,7 +126,7 @@ extension TorusUtils { internal func generateParams(message: String, privateKey: String) throws -> MetadataParams { let privKey = try SecretKey(hex: privateKey) - let publicKey = try privKey.to_public().serialize(compressed: false) + let publicKey = try privKey.toPublic().serialize(compressed: false) let timeStamp = String(BigUInt(serverTimeOffset + Date().timeIntervalSince1970), radix: 16) let setData: MetadataParams.SetData = .init(data: message, timestamp: timeStamp) @@ -130,7 +136,7 @@ extension TorusUtils { .encode(setData) let hash = keccak256Data(encodedData).hexString - let sigData = try CurveSecp256k1.signForRecovery(hash: hash, privateKey: privKey).serialize() + let sigData = try ECDSA.signRecoverable(key: privKey, hash: hash).serialize() return .init(pub_key_X: String(publicKey.suffix(128).prefix(64)), pub_key_Y: String(publicKey.suffix(64)), setData: setData, signature: Data(hex: sigData).base64EncodedString()) } @@ -200,7 +206,7 @@ extension TorusUtils { } let derivedPrivateKey = try SecretKey(hex: try lagrangeInterpolation(shares: currentCombiShares, offset: 0).addLeading0sForLength64()) - let decryptedPubKey = try derivedPrivateKey.to_public().serialize(compressed: false) + let decryptedPubKey = try derivedPrivateKey.toPublic().serialize(compressed: false) let decryptedPubKeyX = String(decryptedPubKey.suffix(128).prefix(64)) let decryptedPubKeyY = String(decryptedPubKey.suffix(64)) if decryptedPubKeyX == thresholdPublicKey.X.addLeading0sForLength64() && decryptedPubKeyY == thresholdPublicKey.Y.addLeading0sForLength64() { @@ -231,7 +237,7 @@ extension TorusUtils { let threshold = (endpoints.count / 2) + 1 let sessionAuthKey = SecretKey() - let serializedPublicKey = try sessionAuthKey.to_public().serialize(compressed: false) + let serializedPublicKey = try sessionAuthKey.toPublic().serialize(compressed: false) // Split key in 2 parts, X and Y let pubKeyX = String(serializedPublicKey.suffix(128).prefix(64)) @@ -441,7 +447,7 @@ extension TorusUtils { let derivedPrivateKey = try SecretKey(hex: oAuthKey) - let oAuthPubKey = try derivedPrivateKey.to_public().serialize(compressed: false) + let oAuthPubKey = try derivedPrivateKey.toPublic().serialize(compressed: false) let oAuthPubKeyX = String(oAuthPubKey.suffix(128).prefix(64)) let oAuthPubKeyY = String(oAuthPubKey.suffix(64)) @@ -661,7 +667,7 @@ extension TorusUtils { public func encryptData(privkeyHex: String, _ dataToEncrypt: String) throws -> String { let privKey = try SecretKey(hex: privkeyHex) - let pubKey = try privKey.to_public().serialize(compressed: false) + let pubKey = try privKey.toPublic().serialize(compressed: false) let encParams = try encrypt(publicKey: pubKey, msg: dataToEncrypt, opts: nil) let data = try JSONEncoder().encode(encParams) guard let string = String(data: data, encoding: .utf8) else { throw TorusUtilError.runtime("Invalid String from enc Params") } @@ -679,9 +685,9 @@ extension TorusUtils { public func encrypt(publicKey: String, msg: String, opts: Ecies? = nil) throws -> Ecies { let ephemPrivateKey = SecretKey() - let ephemPublicKey = try ephemPrivateKey.to_public() + let ephemPublicKey = try ephemPrivateKey.toPublic() - let sharedSecret = try CurveSecp256k1.ecdh(publicKey: ephemPublicKey, privateKey: ephemPrivateKey) + let sharedSecret = try ecdh_sha512(publicKey: ephemPublicKey, privateKey: ephemPrivateKey) let encryptionKey = Array(sharedSecret[0 ..< 32]) let macKey = Array(sharedSecret[32 ..< 64]) @@ -707,7 +713,7 @@ extension TorusUtils { let nodeIndex = el.key let publicKeyHex = el.value.ephemPublicKey - let sharedSecret = try CurveSecp256k1.ecdhWithHex(pubKeyHex: publicKeyHex, privateKeyHex: privateKey) + let sharedSecret = try ecdh_sha512(publicKey: PublicKey(hex: publicKeyHex), privateKey: SecretKey(hex: privateKey)) guard let data = Data(base64Encoded: el.value.share), @@ -745,7 +751,7 @@ extension TorusUtils { do { let data = try lagrangeInterpolation(shares: sharesToInterpolate) let finalPrivateKey = try SecretKey(hex: data) - let finalPublicKey = try finalPrivateKey.to_public().serialize(compressed: false) + let finalPublicKey = try finalPrivateKey.toPublic().serialize(compressed: false) // Split key in 2 parts, X and Y let pubKeyX = String(finalPublicKey.suffix(128).prefix(64)) let pubKeyY = String(finalPublicKey.suffix(64)) @@ -1206,7 +1212,7 @@ extension TorusUtils { internal func generateNonceMetadataParams(message: String, privateKey: BigInt, nonce: BigInt?) throws -> NonceMetadataParams { let privKey = try SecretKey(hex: privateKey.magnitude.serialize().hexString.addLeading0sForLength64()) - let publicKey = try privKey.to_public().serialize(compressed: false) + let publicKey = try privKey.toPublic().serialize(compressed: false) let timeStamp = String(BigUInt(serverTimeOffset + Date().timeIntervalSince1970), radix: 16) var setData: NonceMetadataParams.SetNonceData = .init(data: message, timestamp: timeStamp) @@ -1218,7 +1224,7 @@ extension TorusUtils { let encodedData = try JSONEncoder() .encode(setData) let hash = keccak256Data(encodedData).hexString - let sigData = try CurveSecp256k1.signForRecovery(hash: hash, privateKey: privKey).serialize() + let sigData = try ECDSA.signRecoverable(key: privKey, hash: hash).serialize() return .init(pub_key_X: String(publicKey.suffix(128).prefix(64)), pub_key_Y: String(publicKey.suffix(64)), setData: setData, signature: Data(hex: sigData).base64EncodedString()) } @@ -1236,13 +1242,13 @@ extension TorusUtils { } internal func combinePublicKeys(keys: [String], compressed: Bool) throws -> String { - let collection = PublicKeyCollection(); + let collection = PublicKeyCollection() for item in keys { let pk = try PublicKey(hex: item) try collection.insert(key: pk) } - - let added = try CurveSecp256k1.combineSerializedPublicKeys(keys: collection, outputCompressed: compressed) + + let added = try PublicKey.combine(collection: collection).serialize(compressed: compressed) return added } @@ -1264,7 +1270,7 @@ extension TorusUtils { finalPubKey = (pubKeyX.addLeading0sForLength64() + pubKeyY.addLeading0sForLength64()).add04Prefix() if nonce != BigInt(0) { let noncePrivateKey = try SecretKey(hex: BigUInt(nonce).magnitude.serialize().addLeading0sForLength64().hexString) - let noncePublicKey = try noncePrivateKey.to_public().serialize(compressed: false) + let noncePublicKey = try noncePrivateKey.toPublic().serialize(compressed: false) finalPubKey = try combinePublicKeys(keys: [finalPubKey, noncePublicKey], compressed: false) } else { finalPubKey = String(finalPubKey) @@ -1293,7 +1299,7 @@ extension TorusUtils { if localNonce != BigInt(0) { let nonce2 = BigInt(localNonce) let noncePrivateKey = try SecretKey(hex: BigUInt(nonce2).magnitude.serialize().addLeading0sForLength64().hexString) - let noncePublicKey = try noncePrivateKey.to_public().serialize(compressed: false) + let noncePublicKey = try noncePrivateKey.toPublic().serialize(compressed: false) finalPubKey = try combinePublicKeys(keys: [finalPubKey, noncePublicKey], compressed: false) } else { finalPubKey = String(finalPubKey) @@ -1342,7 +1348,7 @@ extension TorusUtils { } public func decrypt(privateKey: String, opts: ECIES, padding: Padding = .pkcs7) throws -> Data { - let sharedSecret = try CurveSecp256k1.ecdhWithHex(pubKeyHex: opts.ephemPublicKey, privateKeyHex: privateKey) + let sharedSecret = try ecdh_sha512(publicKey: PublicKey(hex: opts.ephemPublicKey), privateKey: SecretKey(hex: privateKey)) let aesKey = Array(sharedSecret[0 ..< 32]) _ = Array(sharedSecret[32 ..< 64]) // TODO: check mac diff --git a/Sources/TorusUtils/TorusUtils.swift b/Sources/TorusUtils/TorusUtils.swift index eb6e3e7d..0aed56ba 100644 --- a/Sources/TorusUtils/TorusUtils.swift +++ b/Sources/TorusUtils/TorusUtils.swift @@ -232,7 +232,7 @@ open class TorusUtils: AbstractTorusUtils { indexes: [BigUInt], endpoints: [String], verifier: String, verifierId: String, idToken: String, extraParams: [String: Codable]) async throws -> TorusKey { let privateKey = SecretKey() - let serializedPublicKey = try privateKey.to_public().serialize(compressed: false) + let serializedPublicKey = try privateKey.toPublic().serialize(compressed: false) // Split key in 2 parts, X and Y // let publicKeyHex = publicKey.toHexString() @@ -287,7 +287,7 @@ open class TorusUtils: AbstractTorusUtils { let serializedKey = privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64() let finalPrivateKey = try SecretKey(hex: serializedKey) - finalPubKey = try finalPrivateKey.to_public().serialize(compressed: false) + finalPubKey = try finalPrivateKey.toPublic().serialize(compressed: false) } } else { // for imported keys in legacy networks @@ -295,7 +295,7 @@ open class TorusUtils: AbstractTorusUtils { var privateKeyWithNonce = BigInt(metadataNonce) + BigInt(oAuthKey, radix: 16)! privateKeyWithNonce = privateKeyWithNonce.modulus(modulusValue) let finalPrivateKey = try SecretKey(hex: privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64()) - finalPubKey = try finalPrivateKey.to_public().serialize(compressed: false) + finalPubKey = try finalPrivateKey.toPublic().serialize(compressed: false) } let oAuthKeyAddress = generateAddressFromPubKey(publicKeyX: oAuthKeyX, publicKeyY: oAuthKeyY)