diff --git a/Sources/ThresholdKey/Common/KeyPoint.swift b/Sources/ThresholdKey/Common/KeyPoint.swift index 477881f..bd2ff5d 100644 --- a/Sources/ThresholdKey/Common/KeyPoint.swift +++ b/Sources/ThresholdKey/Common/KeyPoint.swift @@ -1,16 +1,17 @@ -// -// Point.swift -// tkey_ios -// -// Created by David Main on 2022/11/01. -// - import Foundation #if canImport(lib) import lib #endif public final class KeyPoint: Equatable { + + /// Compares two KeyPoint objects + /// + /// - Parameters: + /// - lhs: First `KeyPoint` to compare. + /// - rhs: Second `Keypoint` to compare. + /// + /// - Returns: `true` if they are equal, `false` otherwise public static func == (lhs: KeyPoint, rhs: KeyPoint) -> Bool { do { let lhsx = try lhs.getX() @@ -30,10 +31,25 @@ public final class KeyPoint: Equatable { public var pointer: OpaquePointer? + /// Instantiate a `KeyPoint` object using the underlying pointer. + /// + /// - Returns: `KeyPoint` + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. public init(pointer: OpaquePointer) { self.pointer = pointer } + /// Instantiates a `KeyPoint` object using X and Y co-ordinates in hexadecimal format. + /// + /// - Parameters: + /// - x: X value of co-ordinate pair. + /// - y: Y value of co-ordinate pair. + /// + /// - Returns: `KeyPoint` object. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used. public init(x: String, y: String) throws { var errorCode: Int32 = -1 let xPtr = UnsafeMutablePointer(mutating: (x as NSString).utf8String) @@ -47,6 +63,11 @@ public final class KeyPoint: Equatable { pointer = result; } + /// Retrieves the X value of the co-ordinate pair. + /// + /// - Returns: X value in hexadecimal format as `String` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func getX() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in @@ -60,6 +81,11 @@ public final class KeyPoint: Equatable { return x } + /// Retrieves the Y value of the co-ordinate pair. + /// + /// - Returns: Y value in hexadecimal format as `String` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func getY() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in @@ -73,15 +99,23 @@ public final class KeyPoint: Equatable { return y } + /// Gets the serialized form of a `KeyPoint`, should it be a valid PublicKey. + /// + /// - Parameters: + /// - format: `"elliptic-compressed"` for the compressed form, otherwise the uncompressed form will be returned. + /// + /// - Returns: Serialized form of `KeyPoint` as `String` + /// + /// - Throws: `RuntimeError`, indicates either the underlying pointer is invalid or the co-ordinate pair is not a valid PublicKey. public func getAsCompressedPublicKey(format: String) throws -> String { var errorCode: Int32 = -1 - let encoder_format = UnsafeMutablePointer(mutating: ("elliptic-compressed" as NSString).utf8String) + let encoder_format = UnsafeMutablePointer(mutating: (format as NSString).utf8String) let result = withUnsafeMutablePointer(to: &errorCode, { error in key_point_encode(pointer, encoder_format, error) }) guard errorCode == 0 else { - throw RuntimeError("Error in KeyPoint, field Y") + throw RuntimeError("Error in KeyPoint, getAsCompressedPublicKey") } let compressed = String.init(cString: result!) string_free(result) diff --git a/Sources/ThresholdKey/Common/PrivateKey.swift b/Sources/ThresholdKey/Common/PrivateKey.swift index 0850ea9..d6c9fb6 100644 --- a/Sources/ThresholdKey/Common/PrivateKey.swift +++ b/Sources/ThresholdKey/Common/PrivateKey.swift @@ -1,10 +1,3 @@ -// -// PrivateKey.swift -// tkey_ios (iOS) -// -// Created by David Main on 2022/11/01. -// - import Foundation #if canImport(lib) import lib @@ -14,15 +7,32 @@ public final class PrivateKey { public var hex: String internal static let curveN = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" + /// Instantiate a `PrivateKey` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `PrivateKey` object. public init(pointer: UnsafeMutablePointer) { hex = String.init(cString: pointer) string_free(pointer) } + /// Instantiates a `PrivateKey` object from its' serialized format. + /// + /// - Parameters: + /// - hex: hexadecimal representation as `String` + /// + /// - Returns: `PrivateKey` object. public init(hex: String) { self.hex = hex } + /// Instantiates a `PrivateKey` object by random generation. + /// + /// - Returns: `PrivateKey` object. + /// + /// - Throws: `RuntimeError`, only possible if curveN is passed externally. public static func generate() throws -> PrivateKey { var errorCode: Int32 = -1 let curvePointer = UnsafeMutablePointer(mutating: (curveN as NSString).utf8String) diff --git a/Sources/ThresholdKey/Common/ShareStore.swift b/Sources/ThresholdKey/Common/ShareStore.swift index 9e4428c..9bcf6ad 100644 --- a/Sources/ThresholdKey/Common/ShareStore.swift +++ b/Sources/ThresholdKey/Common/ShareStore.swift @@ -1,10 +1,3 @@ -// -// ShareStore.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -12,11 +5,25 @@ import Foundation public final class ShareStore { private(set) var pointer: OpaquePointer? - + + /// Instantiate a `ShareStore` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `ShareStore` public init(pointer: OpaquePointer) { self.pointer = pointer } + /// Instantiate a `ShareStore` object using its' corresponding json. + /// + /// - Parameters: + /// - json: Json representation as a `String`. + /// + /// - Returns: `ShareStore` + /// + /// - Throws: `RuntimeError`, json is invalid. public init(json: String) throws { var errorCode: Int32 = -1 let jsonPointer = UnsafeMutablePointer(mutating: (json as NSString).utf8String) @@ -24,57 +31,77 @@ public final class ShareStore { share_store_from_json(jsonPointer, error) }) guard errorCode == 0 else { - throw RuntimeError("Error in ShareStore \(errorCode)") + throw RuntimeError("Error in ShareStore, json") } pointer = result } + /// Serialize a `ShareStore` object to its' corresponding json. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, underlying pointer is invalid public func toJsonString() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in share_store_to_json(pointer, error) }) guard errorCode == 0 else { - throw RuntimeError("Error in ShareStore to Json \(errorCode)") + throw RuntimeError("Error in ShareStore toJsonString") } let string = String(cString: result!) string_free(result) return string } + /// Returns the Share contained in the `ShareStore` object. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, underlying pointer is invalid public func share() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in share_store_get_share(pointer, error) }) guard errorCode == 0 else { - throw RuntimeError("Error in ShareStore") + throw RuntimeError("Error in ShareStore, share") } let value = String.init(cString: result!) string_free(result) return value } + /// Returns the share index of the Share contained in the `ShareStore` object. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, underlying pointer is invalid public func share_index() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in share_store_get_share_index(pointer, error) }) guard errorCode == 0 else { - throw RuntimeError("Error in ShareStore") + throw RuntimeError("Error in ShareStore, share index") } let value = String.init(cString: result!) string_free(result) return value } + /// Returns the polynomial ID of the `ShareStore` object. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, underlying pointer is invalid public func polynomial_id() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in share_store_get_polynomial_id(pointer, error) }) guard errorCode == 0 else { - throw RuntimeError("Error in ShareStore") + throw RuntimeError("Error in ShareStore, polynomial id") } let value = String.init(cString: result!) string_free(result) diff --git a/Sources/ThresholdKey/GenerateShareStoreResult.swift b/Sources/ThresholdKey/GenerateShareStoreResult.swift index 2901acd..046ff77 100644 --- a/Sources/ThresholdKey/GenerateShareStoreResult.swift +++ b/Sources/ThresholdKey/GenerateShareStoreResult.swift @@ -1,10 +1,3 @@ -// -// GenerateShareStoreResult.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -15,6 +8,14 @@ public final class GenerateShareStoreResult { public var hex: String public var share_store: ShareStoreMap + /// Instantiate a `GenerateShareStoreResult` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `GenerateShareStoreResult` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) throws { self.pointer = pointer var errorCode: Int32 = -1 diff --git a/Sources/ThresholdKey/KeyDetails.swift b/Sources/ThresholdKey/KeyDetails.swift index e986c82..7a1ed9c 100644 --- a/Sources/ThresholdKey/KeyDetails.swift +++ b/Sources/ThresholdKey/KeyDetails.swift @@ -1,10 +1,3 @@ -// -// KeyResult.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -17,6 +10,14 @@ public final class KeyDetails { public let total_shares: UInt32 public let share_descriptions: String + /// Instantiate a `KeyDetails` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `KeyDetails` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) throws { var errorCode: Int32 = -1 let point = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/KeyPointArray.swift b/Sources/ThresholdKey/KeyPointArray.swift index 17e9f1e..57ca029 100644 --- a/Sources/ThresholdKey/KeyPointArray.swift +++ b/Sources/ThresholdKey/KeyPointArray.swift @@ -1,10 +1,3 @@ -// -// File.swift -// -// -// Created by guru ramu on 01/02/23. -// - import Foundation #if canImport(lib) @@ -14,14 +7,26 @@ import Foundation public class KeyPointArray { private(set) var pointer: OpaquePointer? + /// Instantiate a new `KeyPointArray` object. + /// + /// - Returns: `KeyPointArray` public init() { self.pointer = key_point_array_new(); } + /// Instantiate a `KeyPointArray` object using the underlying pointer. + /// + /// - Returns: `KeyPointArray` public init(pointer: OpaquePointer) { self.pointer = pointer; } + /// Removes a `KeyPoint` from the collection at a specified index. + /// + /// - Parameters: + /// - index: Index for removal. + /// + /// - Throws: `RuntimeError`, indicates invalid index or invalid `KeyPointArray`. public func removeAt(index: Int32) throws { var errorCode: Int32 = -1 @@ -33,6 +38,12 @@ public class KeyPointArray { } } + /// Inserts a `KeyPoint` into the collection at the end. + /// + /// - Parameters: + /// - point: `KeyPoint` to be added. + /// + /// - Throws: `RuntimeError`, indicates invalid `KeyPoint` or invalid `KeyPointArray`. public func insert(point: KeyPoint) throws { var errorCode: Int32 = -1 withUnsafeMutablePointer(to: &errorCode, { error in @@ -43,6 +54,13 @@ public class KeyPointArray { } } + /// Replaces a `KeyPoint` in the collection at a specified index. + /// + /// - Parameters: + /// - point: `KeyPoint` used for replacement. + /// - index: index of `KeyPoint` to be replaced. + /// + /// - Throws: `RuntimeError`, indicates invalid `KeyPoint`, index or invalid `KeyPointArray`. public func update(point: KeyPoint, index: Int32) throws { var errorCode: Int32 = -1 @@ -54,6 +72,14 @@ public class KeyPointArray { } } + /// Retrieves a `KeyPoint` in the collection at a specified index. + /// + /// - Parameters: + /// - index: index of `KeyPoint` to be retrieved. + /// + /// - Returns: `KeyPoint` + /// + /// - Throws: `RuntimeError`, indicates invalid index or invalid `KeyPointArray`. public func getAt(index: Int32) throws -> KeyPoint { var errorCode: Int32 = -1 @@ -64,8 +90,13 @@ public class KeyPointArray { throw RuntimeError("Error in KeyPointArray, key_point_array_get_value_by_index") } return KeyPoint.init(pointer: key_point!); - } + } + /// Number of items contained in the collection. + /// + /// - Returns: `Int32` + /// + /// - Throws: `RuntimeError`, invalid `KeyPointArray`. public func length() throws -> Int32 { var errorCode: Int32 = -1 @@ -79,10 +110,14 @@ public class KeyPointArray { } + /// Performs lagrange interpolation on the items contained in the collection. + /// + /// - Returns: `Polynomial` + /// + /// - Throws: `RuntimeError`, indicates invalid `KeyPointArray`. public func lagrange() throws -> Polynomial { var errorCode: Int32 = -1 - let curveN = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" let curvePointer = UnsafeMutablePointer(mutating: (curveN as NSString).utf8String) diff --git a/Sources/ThresholdKey/KeyReconstructionDetails.swift b/Sources/ThresholdKey/KeyReconstructionDetails.swift index be939a5..088e439 100644 --- a/Sources/ThresholdKey/KeyReconstructionDetails.swift +++ b/Sources/ThresholdKey/KeyReconstructionDetails.swift @@ -1,10 +1,3 @@ -// -// ReconstructionResult.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -15,6 +8,14 @@ public final class KeyReconstructionDetails: Codable { public var seed_phrase: [String] public var all_keys: [String] + /// Instantiate a `KeyReconstructionDetails` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `KeyReconstructionDetails` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) throws { var errorCode: Int32 = -1 let key = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/LocalMetadataTransitions.swift b/Sources/ThresholdKey/LocalMetadataTransitions.swift index 411f213..1ed97d2 100644 --- a/Sources/ThresholdKey/LocalMetadataTransitions.swift +++ b/Sources/ThresholdKey/LocalMetadataTransitions.swift @@ -1,10 +1,3 @@ -// -// LocalMetadataTransitions.swift -// -// -// Created by David Main on 2023/01/11. -// - import Foundation #if canImport(lib) @@ -14,10 +7,26 @@ import Foundation public final class LocalMetadataTransitions { private(set) var pointer: OpaquePointer? + /// Instantiate a `LocalMetadataTransitions` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `LocalMetadataTransitions` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) { self.pointer = pointer } + /// Instantiate a `LocalMetadataTransitions` object using the json representation. + /// + /// - Parameters: + /// - json: Json representation as `String`. + /// + /// - Returns: `LocalMetadataTransitions` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(json: String) throws { var errorCode: Int32 = -1 let jsonPointer = UnsafeMutablePointer(mutating: (json as NSString).utf8String) @@ -29,7 +38,12 @@ public final class LocalMetadataTransitions { } pointer = result } - + + /// Serialize to json + /// + /// - Returns:`String` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func export() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/Metadata.swift b/Sources/ThresholdKey/Metadata.swift index cafcc5e..bcfd3ed 100644 --- a/Sources/ThresholdKey/Metadata.swift +++ b/Sources/ThresholdKey/Metadata.swift @@ -1,10 +1,3 @@ -// -// Metadata.swift -// tkey_ios -// -// Created by David Main on 2022/12/06. -// - import Foundation #if canImport(lib) import lib @@ -13,10 +6,26 @@ import Foundation public final class Metadata { private(set) var pointer: OpaquePointer? + /// Instantiate a `Metadata` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `Metadata` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer?) { self.pointer = pointer } + /// Instantiate a `Metadata` object using the json representation. + /// + /// - Parameters: + /// - json: Json representation as `String`. + /// + /// - Returns: `Metadata` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(json: String) throws { var errorCode: Int32 = -1 let jsonPointer = UnsafeMutablePointer(mutating: (json as NSString).utf8String) @@ -29,6 +38,11 @@ public final class Metadata { pointer = result } + /// Serialize to json + /// + /// - Returns:`String` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func export() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/Modules/PrivateKeysModule.swift b/Sources/ThresholdKey/Modules/PrivateKeysModule.swift index 58c6fe5..e7f6b71 100644 --- a/Sources/ThresholdKey/Modules/PrivateKeysModule.swift +++ b/Sources/ThresholdKey/Modules/PrivateKeysModule.swift @@ -1,10 +1,3 @@ -// -// PrivateKeysModule.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -41,6 +34,15 @@ public final class PrivateKeysModule { } } + /// Sets an extra private key on an existing `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - key: The private key to set in hexadecimal format. Optional, will be generated on the Secp256k1 curve if not supplied. + /// - format: "secp256k1n" is currently the only cupported format. + /// + /// - Returns: `true` if key was set, `false` otherwise. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func set_private_key(threshold_key: ThresholdKey, key: String?, format: String ) async throws -> Bool { return try await withCheckedThrowingContinuation { continuation in @@ -56,6 +58,13 @@ public final class PrivateKeysModule { } } + /// Returns stored extra private keys on an existing `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// + /// - Returns: Array of `KeyData`. + /// + /// - Throws: `RuntimeError`, indicates invalid threshold key. public static func get_private_keys(threshold_key: ThresholdKey) throws -> [KeyData] { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in @@ -71,6 +80,13 @@ public final class PrivateKeysModule { return keys } + /// Returns accounts of stored extra private keys on an existing `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// + /// - Returns: Array of `String`. + /// + /// - Throws: `RuntimeError`, indicates invalid threshold key. public static func get_private_key_accounts(threshold_key: ThresholdKey) throws -> [String] { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/Modules/SecurityQuestionModule.swift b/Sources/ThresholdKey/Modules/SecurityQuestionModule.swift index 1f18166..a374d46 100644 --- a/Sources/ThresholdKey/Modules/SecurityQuestionModule.swift +++ b/Sources/ThresholdKey/Modules/SecurityQuestionModule.swift @@ -1,10 +1,3 @@ -// -// SecurityQuestionModule.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -33,6 +26,15 @@ public final class SecurityQuestionModule { } } + /// Generates a new security share on an existing `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - question: The security question. + /// - answer: The answer for the security question. + /// + /// - Returns: `GenerateShareStoreResult` object. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func generate_new_share(threshold_key: ThresholdKey, questions: String, answer: String ) async throws -> GenerateShareStoreResult { return try await withCheckedThrowingContinuation { continuation in @@ -70,6 +72,14 @@ public final class SecurityQuestionModule { } } + /// Inputs a stored security share into an existing `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - answer: The answer for the security question of the stored share. + /// + /// - Returns: `true` on success, `false` otherwise. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func input_share(threshold_key: ThresholdKey, answer: String ) async throws -> Bool { return try await withCheckedThrowingContinuation { continuation in @@ -105,6 +115,15 @@ public final class SecurityQuestionModule { } } + /// Changes the question and answer for an existing security share on a `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - question: The security question. + /// - answer: The answer for the security question. + /// + /// - Returns: `true` on success, `false` otherwise. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func change_question_and_answer(threshold_key: ThresholdKey, questions: String, answer: String ) async throws -> Bool { return try await withCheckedThrowingContinuation { continuation in @@ -120,6 +139,7 @@ public final class SecurityQuestionModule { } } + private static func store_answer(threshold_key: ThresholdKey, answer: String, completion: @escaping (Result) -> Void) { threshold_key.tkeyQueue.async { do { @@ -139,6 +159,14 @@ public final class SecurityQuestionModule { } } + /// Saves the answer for an existing security share on a `ThresholdKey` object to the tkey store. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - answer: The answer for the security question. + /// + /// - Returns: `true` on success, `false` otherwise. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func store_answer(threshold_key: ThresholdKey, answer: String ) async throws -> Bool { return try await withCheckedThrowingContinuation { continuation in @@ -154,6 +182,10 @@ public final class SecurityQuestionModule { } } + /// Retrieves the answer for an existing security share on a `ThresholdKey`. + /// - Returns: `String`. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func get_answer(threshold_key: ThresholdKey) throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in @@ -167,6 +199,10 @@ public final class SecurityQuestionModule { return string } + /// Retrieves the question for an existing security share on a `ThresholdKey`. + /// - Returns: `String`. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func get_questions(threshold_key: ThresholdKey) throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/Modules/SeedPhraseModule.swift b/Sources/ThresholdKey/Modules/SeedPhraseModule.swift index 62f52c8..25da1a6 100644 --- a/Sources/ThresholdKey/Modules/SeedPhraseModule.swift +++ b/Sources/ThresholdKey/Modules/SeedPhraseModule.swift @@ -1,16 +1,9 @@ -// -// SeedPhraseModule.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib #endif -public struct seedPhraseStruct: Codable { +public struct SeedPhrase: Codable { public var seedPhrase: String public var type: String } @@ -40,6 +33,14 @@ public final class SeedPhraseModule { } } + /// Sets a seed phrase on the metadata of a `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - format: "HD Key Tree" is the only supported format. + /// - phrase: The seed phrase. Optional, will be generated if not provided. + /// - number_of_wallets: Number of children derived from this seed phrase. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func set_seed_phrase(threshold_key: ThresholdKey, format: String, phrase: String?, number_of_wallets: UInt32 ) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -75,6 +76,13 @@ public final class SeedPhraseModule { } } + /// Replaces an old seed phrase with a new seed phrase on a `ThresholdKey` object. Same format of seed phrase must be used. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - old_phrase: The original seed phrase. + /// - new_phrase: The replacement phrase. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func change_phrase(threshold_key: ThresholdKey, old_phrase: String, new_phrase: String ) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -90,7 +98,13 @@ public final class SeedPhraseModule { } } - public static func get_seed_phrases(threshold_key: ThresholdKey) throws -> [seedPhraseStruct] { + /// Returns the seed phrases stored on a `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// + /// - Returns: Array of SeedPhrase objects. + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. + public static func get_seed_phrases(threshold_key: ThresholdKey) throws -> [SeedPhrase] { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in seed_phrase_get_seed_phrases(threshold_key.pointer, error) @@ -101,7 +115,7 @@ public final class SeedPhraseModule { let string = String.init(cString: result!) string_free(result) let decoder = JSONDecoder() - let seed_array = try! decoder.decode( [seedPhraseStruct].self, from: string.data(using: String.Encoding.utf8)! ) + let seed_array = try! decoder.decode( [SeedPhrase].self, from: string.data(using: String.Encoding.utf8)! ) return seed_array } @@ -125,6 +139,12 @@ public final class SeedPhraseModule { } } + /// Deletes a seed phrase stored on a `ThresholdKey` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - phrase: The phrase to be deleted. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func delete_seed_phrase(threshold_key: ThresholdKey, phrase: String ) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -139,6 +159,7 @@ public final class SeedPhraseModule { } } } + /* static func get_seed_phrases_with_accounts(threshold_key: ThresholdKey, derivation_format: String) throws -> String { diff --git a/Sources/ThresholdKey/Modules/ShareSerializationModule.swift b/Sources/ThresholdKey/Modules/ShareSerializationModule.swift index 20e6215..590e40c 100644 --- a/Sources/ThresholdKey/Modules/ShareSerializationModule.swift +++ b/Sources/ThresholdKey/Modules/ShareSerializationModule.swift @@ -1,16 +1,18 @@ -// -// ShareSerializationModule.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib #endif public final class ShareSerializationModule { + /// Serializes a share on a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - format: Optional, can either be nil or `"mnemonic"`. + /// - share: Share to be serialized. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func serialize_share(threshold_key: ThresholdKey, share: String, format: String? = nil) throws -> String { var errorCode: Int32 = -1 @@ -32,6 +34,15 @@ public final class ShareSerializationModule { return value } + /// Deserialize a share on a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - format: Optional, can either be nil or `"mnemonic"`. + /// - share: Share to be serialized. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func deserialize_share(threshold_key: ThresholdKey, share: String, format: String? = nil) throws -> String { var errorCode: Int32 = -1 diff --git a/Sources/ThresholdKey/Modules/ShareTransferModule.swift b/Sources/ThresholdKey/Modules/ShareTransferModule.swift index 7c03eab..a1dfa17 100644 --- a/Sources/ThresholdKey/Modules/ShareTransferModule.swift +++ b/Sources/ThresholdKey/Modules/ShareTransferModule.swift @@ -1,16 +1,18 @@ -// -// ShareTransferModule.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib #endif public final class ShareTransferModule { + /// This module facilitates the transfer of shares between devices, this ensure that both devies can share the same private key. The service provider configuration will need to be the same for both instances of the `ThresholdKey`. This is particularly useful where a user would want to share a login between multiple devices that they control without ending up with a common share between them after the process is complete. + /// Device A will fully reconstruct the `ThresholdKey`. + /// Device B will be initialized in the same way as Device A. + /// Device B will request a share from Device A. + /// Device A will then lookup and approve the share request for Device B. + /// Device B would then check the status of the request until it is approved. + /// Device B would then be able to reconstruct the `ThresholdKey`, reaching the same private key as Device A. + /// Device B would then cleanup the share request, automatic if enabled. + private static func request_new_share(threshold_key: ThresholdKey, user_agent: String, available_share_indexes: String, completion: @escaping (Result) -> Void) { threshold_key.tkeyQueue.async { do { @@ -33,6 +35,15 @@ public final class ShareTransferModule { } } + /// Requests a new share for transfer for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - user_agent: `String` containing information about the device requesting the share. + /// - available_share_indexes: Json represented as a `String` indicating the available share indexes on which the transfer should take place, can be an empty array `"[]"` + /// + /// - Returns: `String`, the encryption key. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func request_new_share(threshold_key: ThresholdKey, user_agent: String, available_share_indexes: String ) async throws -> String { return try await withCheckedThrowingContinuation { continuation in @@ -68,6 +79,13 @@ public final class ShareTransferModule { } } + /// Adds custom information to a share transfer request for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - enc_pub_key_x: The encryption key for the share transfer request. + /// - custom_info: Json represented as a `String`, the custom information to be added. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func add_custom_info_to_request(threshold_key: ThresholdKey, enc_pub_key_x: String, custom_info: String ) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -103,6 +121,13 @@ public final class ShareTransferModule { } } + /// Searches for available share transfer requests for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// + /// - Returns: Array of `String` + /// + /// - Throws: `RuntimeError`, indicates invalid threshold key. public static func look_for_request(threshold_key: ThresholdKey ) async throws -> [String] { return try await withCheckedThrowingContinuation { continuation in @@ -119,14 +144,19 @@ public final class ShareTransferModule { } - private static func approve_request(threshold_key: ThresholdKey, enc_pub_key_x: String, share_store: ShareStore, completion: @escaping (Result) -> Void) { + private static func approve_request(threshold_key: ThresholdKey, enc_pub_key_x: String, share_store: ShareStore? = nil, completion: @escaping (Result) -> Void) { threshold_key.tkeyQueue.async { do { var errorCode: Int32 = -1 + var storePointer: OpaquePointer? + + if share_store != nil { + storePointer = share_store!.pointer + } let curvePointer = UnsafeMutablePointer(mutating: (threshold_key.curveN as NSString).utf8String) let encPointer = UnsafeMutablePointer(mutating: (enc_pub_key_x as NSString).utf8String) withUnsafeMutablePointer(to: &errorCode, { error in - share_transfer_approve_request(threshold_key.pointer, encPointer, share_store.pointer, curvePointer, error) + share_transfer_approve_request(threshold_key.pointer, encPointer, storePointer, curvePointer, error) }) guard errorCode == 0 else { throw RuntimeError("Error in ShareTransferModule, change_question_and_answer. Error Code: \(errorCode)") @@ -138,7 +168,14 @@ public final class ShareTransferModule { } } - public static func approve_request(threshold_key: ThresholdKey, enc_pub_key_x: String, share_store: ShareStore ) async throws { + /// Approves a share transfer request for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - enc_pub_key_x: The encryption key for the share transfer request. + /// - share_store: The `ShareStore` for the share transfer request, optional. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. + public static func approve_request(threshold_key: ThresholdKey, enc_pub_key_x: String, share_store: ShareStore? = nil ) async throws { return try await withCheckedThrowingContinuation { continuation in approve_request(threshold_key: threshold_key, enc_pub_key_x: enc_pub_key_x, share_store: share_store) { @@ -173,6 +210,13 @@ public final class ShareTransferModule { } } + /// Approves a share transfer request for a specific share index for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - enc_pub_key_x: The encryption key for the share transfer request. + /// - share_index: The relevant share index for the share transfer request. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func approve_request_with_share_index(threshold_key: ThresholdKey, enc_pub_key_x: String, share_index: String ) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -188,7 +232,6 @@ public final class ShareTransferModule { } } - private static func get_store(threshold_key: ThresholdKey, completion: @escaping (Result) -> Void) { threshold_key.tkeyQueue.async { do { @@ -207,6 +250,12 @@ public final class ShareTransferModule { } } + /// Retrieves the share transfer store for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// + /// - Returns: `ShareTransferStore` + /// - Throws: `RuntimeError`, indicates invalid threshold key. public static func get_store(threshold_key: ThresholdKey ) async throws -> ShareTransferStore { return try await withCheckedThrowingContinuation { continuation in @@ -240,6 +289,13 @@ public final class ShareTransferModule { } } + /// Sets the share transfer store for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - store: The share transfer store. + /// + /// - Returns: `true` on success, `false` otherwise. + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func set_store(threshold_key: ThresholdKey, store: ShareTransferStore ) async throws -> Bool { return try await withCheckedThrowingContinuation { continuation in @@ -275,6 +331,13 @@ public final class ShareTransferModule { } } + /// Removes the share transfer store for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - enc_pub_key_x: The encryption key for the share transfer request. + /// + /// - Returns: `true` on success, `false` otherwise. + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func delete_store(threshold_key: ThresholdKey, enc_pub_key_x: String ) async throws -> Bool { return try await withCheckedThrowingContinuation { continuation in @@ -290,6 +353,11 @@ public final class ShareTransferModule { } } + /// Retrieves the encryption key for the current share transfer request of a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// + /// - Throws: `RuntimeError`, indicates invalid threshold key. public static func get_current_encryption_key(threshold_key: ThresholdKey) throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in @@ -326,6 +394,13 @@ public final class ShareTransferModule { } } + /// Checks the status of a share transfer request for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// - enc_pub_key_x: The encryption key for the share transfer request. + /// - delete_request_on_completion: Determines if the share request should be deleted on completion. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters was used or invalid threshold key. public static func request_status_check(threshold_key: ThresholdKey, enc_pub_key_x: String, delete_request_on_completion: Bool ) async throws -> ShareStore { return try await withCheckedThrowingContinuation { continuation in @@ -341,6 +416,11 @@ public final class ShareTransferModule { } } + /// Clears share transfer requests for a `Threshold Key` object. + /// - Parameters: + /// - threshold_key: The threshold key to act on. + /// + /// - Throws: `RuntimeError`, indicates invalid threshold key. public static func cleanup_request(threshold_key: ThresholdKey) throws { var errorCode: Int32 = -1 withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/Polynomial.swift b/Sources/ThresholdKey/Polynomial.swift index fdfabe3..164765e 100644 --- a/Sources/ThresholdKey/Polynomial.swift +++ b/Sources/ThresholdKey/Polynomial.swift @@ -1,10 +1,3 @@ -// -// File.swift -// -// -// Created by guru ramu on 11/01/23. -// - import Foundation #if canImport(lib) import lib @@ -14,10 +7,24 @@ public final class Polynomial { private(set) var pointer: OpaquePointer? internal let curveN = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" + /// Instantiate a `Polynomial` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `Polynomial` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) { self.pointer = pointer } + /// Retrieves the corresponding `PublicPolynomial` + /// + /// + /// - Returns: `PublicPolynomial` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func getPublicPolynomial() throws -> PublicPolynomial { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in @@ -29,6 +36,14 @@ public final class Polynomial { return PublicPolynomial.init(pointer: result!); } + /// Generates a share at the respective share index. + /// + /// - Parameters: + /// - share_index: Share index to be used. + /// + /// - Returns: `ShareMap` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func generateShares(share_index: String) throws -> ShareMap { var errorCode: Int32 = -1 @@ -43,6 +58,7 @@ public final class Polynomial { } return try! ShareMap.init(pointer: result!); } + deinit { polynomial_free(pointer); } diff --git a/Sources/ThresholdKey/PublicPolynomial.swift b/Sources/ThresholdKey/PublicPolynomial.swift index 703f4bf..877427e 100644 --- a/Sources/ThresholdKey/PublicPolynomial.swift +++ b/Sources/ThresholdKey/PublicPolynomial.swift @@ -1,10 +1,3 @@ -//// -//// File.swift -//// -//// -//// Created by guru ramu on 11/01/23. -//// -// import Foundation #if canImport(lib) import lib @@ -14,10 +7,23 @@ public final class PublicPolynomial { private(set) var pointer: OpaquePointer? internal let curveN = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" + /// Instantiate a `PublicPolynomial` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `Polynomial` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) { self.pointer = pointer; } + /// Threshold for the `PublicPolynomial`. + /// + /// - Returns: `UInt32` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func getThreshold() throws -> UInt32 { var errorCode: Int32 = -1 @@ -30,6 +36,13 @@ public final class PublicPolynomial { return result; } + /// Returns the `KeyPoint` at the respective share index. + /// - Parameters: + /// - index: Share index to be used. + /// + /// - Returns: `KeyPoint` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public func polyCommitmentEval(index: String) throws -> KeyPoint { var errorCode: Int32 = -1 @@ -44,6 +57,7 @@ public final class PublicPolynomial { } return KeyPoint(pointer: result!); } + deinit { public_polynomial_free(pointer); } diff --git a/Sources/ThresholdKey/RuntimeError.swift b/Sources/ThresholdKey/RuntimeError.swift index 564742b..2ccb098 100644 --- a/Sources/ThresholdKey/RuntimeError.swift +++ b/Sources/ThresholdKey/RuntimeError.swift @@ -1,19 +1,21 @@ -// -// RuntimeError.swift -// tkey_ios -// -// Created by David Main on 2022/10/25. -// - import Foundation public struct RuntimeError: Error { public let message: String + /// Instantiate a `RuntimeError` + /// + /// - Parameters: + /// - message: The error description. + /// + /// - Returns: `RuntimeError` public init(_ message: String) { self.message = message } + /// Retrieves the error message. + /// + /// - Returns: `String` public var localizedDescription: String { return message } diff --git a/Sources/ThresholdKey/ServiceProvider.swift b/Sources/ThresholdKey/ServiceProvider.swift index 6ca6e73..100681a 100644 --- a/Sources/ThresholdKey/ServiceProvider.swift +++ b/Sources/ThresholdKey/ServiceProvider.swift @@ -1,10 +1,3 @@ -// -// ServiceProvider.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -14,6 +7,15 @@ public final class ServiceProvider { private(set) var pointer: OpaquePointer? internal let curveN = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" + /// Instantiate a `ServiceProvider` object. + /// + /// - Parameters: + /// - enable_logging: Determines if logging is enabled or not. + /// - postbox_key: The private key to be used for the ServiceProvider. + /// + /// - Returns: `ServiceProvider` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters were used. public init(enable_logging: Bool, postbox_key: String) throws { var errorCode: Int32 = -1 let postboxPointer = UnsafeMutablePointer(mutating: NSString(string: postbox_key).utf8String) diff --git a/Sources/ThresholdKey/ShareMap.swift b/Sources/ThresholdKey/ShareMap.swift index 53122cc..4103f42 100644 --- a/Sources/ThresholdKey/ShareMap.swift +++ b/Sources/ThresholdKey/ShareMap.swift @@ -1,11 +1,3 @@ -// -// File.swift -// -// -// Created by guru ramu on 13/01/23. -// - - import Foundation #if canImport(lib) import lib @@ -14,6 +6,14 @@ import Foundation public final class ShareMap { public var share_map = [String: String]() + /// Instantiate a `ShareMap` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `ShareMap` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) throws { var errorCode: Int32 = -1 let keys = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/ShareStoreArray.swift b/Sources/ThresholdKey/ShareStoreArray.swift index 08ed92e..c921a09 100644 --- a/Sources/ThresholdKey/ShareStoreArray.swift +++ b/Sources/ThresholdKey/ShareStoreArray.swift @@ -1,10 +1,3 @@ -// -// File.swift -// -// -// Created by guru ramu on 01/02/23. -// - import Foundation #if canImport(lib) @@ -14,10 +7,24 @@ import Foundation public class ShareStoreArray { private(set) var pointer: OpaquePointer? - public init(pointer: OpaquePointer) throws { + /// Instantiate a `ShareStoreArray` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `ShareStoreArray` + public init(pointer: OpaquePointer) { self.pointer = pointer } + /// Retrieves a `ShareStore` in the collection at a specified index. + /// + /// - Parameters: + /// - index: index of `ShareStore` to be retrieved. + /// + /// - Returns: `ShareStore` + /// + /// - Throws: `RuntimeError`, indicates invalid index or invalid `KeyPointArray`. public func getAt(index: Int32) throws -> ShareStore { var errorCode: Int32 = -1 @@ -30,6 +37,11 @@ public class ShareStoreArray { return ShareStore.init(pointer: share_store!); } + /// Returns the number of items in the collection. + /// + /// - Returns: `Int32` + /// + /// - Throws: `RuntimeError`, indicates invalid `ShareStoreArray`. public func length() throws -> Int32{ var errorCode: Int32 = -1 diff --git a/Sources/ThresholdKey/ShareStoreMap.swift b/Sources/ThresholdKey/ShareStoreMap.swift index d339335..7a40ec9 100644 --- a/Sources/ThresholdKey/ShareStoreMap.swift +++ b/Sources/ThresholdKey/ShareStoreMap.swift @@ -1,10 +1,3 @@ -// -// ShareStoreMap.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -13,6 +6,14 @@ import Foundation public final class ShareStoreMap { public var share_maps = [String: ShareStore]() + /// Instantiate a `ShareStoreMap` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `ShareStoreMap` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) throws { var errorCode: Int32 = -1 let keys = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Sources/ThresholdKey/ShareStorePolyIdIndexMap.swift b/Sources/ThresholdKey/ShareStorePolyIdIndexMap.swift index 25b6d09..1df3084 100644 --- a/Sources/ThresholdKey/ShareStorePolyIdIndexMap.swift +++ b/Sources/ThresholdKey/ShareStorePolyIdIndexMap.swift @@ -1,10 +1,3 @@ -// -// ShareStorePolyIdIndexMap.swift -// tkey_ios -// -// Created by David Main on 2022/12/13. -// - import Foundation #if canImport(lib) import lib @@ -14,6 +7,14 @@ public final class ShareStorePolyIdIndexMap { private(set) var pointer: OpaquePointer; public var share_maps = [String: ShareStoreMap]() + /// Instantiate a `ShareStorePolyIdIndexMap` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `ShareStorePolyIdIndexMap` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. public init(pointer: OpaquePointer) throws { var errorCode: Int32 = -1 let keys = withUnsafeMutablePointer(to: &errorCode, { error in @@ -43,4 +44,6 @@ public final class ShareStorePolyIdIndexMap { deinit { share_store_poly_id_index_map_free(pointer) } + + //TODO: Class requires a init(json: String) throws method and an export() throws -> String method. } diff --git a/Sources/ThresholdKey/ShareTransferStore.swift b/Sources/ThresholdKey/ShareTransferStore.swift index 387818f..8cc3312 100644 --- a/Sources/ThresholdKey/ShareTransferStore.swift +++ b/Sources/ThresholdKey/ShareTransferStore.swift @@ -13,6 +13,14 @@ import Foundation public final class ShareTransferStore { private(set) var pointer: OpaquePointer? + /// Instantiate a `ShareTransferStore` object using the underlying pointer. + /// + /// - Parameters: + /// - pointer: The pointer to the underlying foreign function interface object. + /// + /// - Returns: `ShareTransferStore` + /// + /// - Throws: `RuntimeError`, indicates underlying pointer is invalid. init(pointer: OpaquePointer) { self.pointer = pointer } diff --git a/Sources/ThresholdKey/StorageLayer.swift b/Sources/ThresholdKey/StorageLayer.swift index 6365537..5dc0193 100644 --- a/Sources/ThresholdKey/StorageLayer.swift +++ b/Sources/ThresholdKey/StorageLayer.swift @@ -1,10 +1,3 @@ -// -// StorageLayer.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -43,7 +36,7 @@ public final class StorageLayer { } */ - public static func percentEscapeString( string: String ) -> String { + private static func percentEscapeString( string: String ) -> String { var characterSet = CharacterSet.alphanumerics characterSet.insert(charactersIn: "-.* ") @@ -53,6 +46,16 @@ public final class StorageLayer { .replacingOccurrences(of: " ", with: "+", options: [], range: nil) } + /// Instantiate a `StorageLayer` object, + /// + /// - Parameters: + /// - enable_logging: Determines whether logging is enabled or not (pending). + /// - host_url: Url for the metadata server. + /// - server_time_offset: Timezone offset for the metadata server. + /// + /// - Returns: `StorageLayer` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters. public init(enable_logging: Bool, host_url: String, server_time_offset: Int64) throws { var errorCode: Int32 = -1 let urlPointer = UnsafeMutablePointer(mutating: (host_url as NSString).utf8String) diff --git a/Sources/ThresholdKey/ThresholdKey.swift b/Sources/ThresholdKey/ThresholdKey.swift index 09395e8..8c227bb 100644 --- a/Sources/ThresholdKey/ThresholdKey.swift +++ b/Sources/ThresholdKey/ThresholdKey.swift @@ -1,10 +1,3 @@ -// -// ThresholdKey.swift -// tkey_ios -// -// Created by David Main. -// - import Foundation #if canImport(lib) import lib @@ -15,6 +8,21 @@ public class ThresholdKey { internal let curveN = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" internal let tkeyQueue = DispatchQueue(label: "thresholdkey.queue") + /// Instantiate a `ThresholdKey` object, + /// + /// - Parameters: + /// - metadata: Existing metadata to be used, optional. + /// - shares: Existing shares to be used, optional. + /// - storage_layer: Storage layer to be used. + /// - service_provider: Service provider to be used, optional only in the most basic usage of tKey. + /// - local_matadata_transitions: Existing local transitions to be used. + /// - last_fetch_cloud_metadata: Existing cloud metadata to be used. + /// - enable_logging: Determines whether logging is available or not (pending). + /// - manual_sync: Determines if changes to the metadata are automatically synced. + /// + /// - Returns: `ThresholdKey` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters. public init(metadata: Metadata? = nil, shares: ShareStorePolyIdIndexMap? = nil, storage_layer: StorageLayer, service_provider: ServiceProvider? = nil, local_matadata_transitions: LocalMetadataTransitions? = nil, last_fetch_cloud_metadata: Metadata? = nil, enable_logging: Bool, manual_sync: Bool) throws { var errorCode: Int32 = -1 var providerPointer: OpaquePointer? @@ -56,6 +64,11 @@ public class ThresholdKey { } + /// Returns the metadata, + /// + /// - Returns: `Metadata` + /// + /// - Throws: `RuntimeError`, indicates invalid underlying poiner. public func get_metadata() throws -> Metadata { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in threshold_key_get_current_metadata(pointer, error)}) @@ -95,18 +108,17 @@ public class ThresholdKey { } } - /** - Initializes a KeyDetails object with the given parameters. - - Parameters: - - import_share: An optional string representing the import share. - input: An optional ShareStore object representing the input. - never_initialize_new_key: A boolean value indicating whether or not to initialize a new key. - include_local_metadata_transitions: A boolean value indicating whether or not to include local metadata transitions. - Returns: A KeyDetails object. - Throws: An error if the function encounters an issue during execution. - */ + /// Initializes a `ThresholdKey` object. + /// + /// - Parameters: + /// - import_share: Share to be imported, optional. + /// - input: `ShareStore` to be used, optional. + /// - never_initialize_new_key: Do not initialize a new tKey if an existing one is found. + /// - include_local_matadata_transitions: Proritize existing metadata transitions over cloud fetched transitions. + /// + /// - Returns: `KeyDetails` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters. public func initialize(import_share: String? = nil, input: ShareStore? = nil, never_initialize_new_key: Bool? = nil, include_local_metadata_transitions: Bool? = nil) async throws -> KeyDetails { return try await withCheckedThrowingContinuation { continuation in @@ -139,10 +151,10 @@ public class ThresholdKey { } } } - /** - Reconstructs the user private key. Minimum threshold number of shares required - */ + /// Reconstructs the private key, this assumes that the number of shares inserted into the `ThrehsoldKey` are equal or greater than the threshold. + /// + /// - Throws: `RuntimeError`. public func reconstruct() async throws -> KeyReconstructionDetails { return try await withCheckedThrowingContinuation { continuation in @@ -158,10 +170,11 @@ public class ThresholdKey { } } - /** - This function returns the latest polynomial that was used in the reconstruction process as a Polynomial object. It throws an error if an error occurs while retrieving the polynomial. - */ - + /// Returns the latest polynomial. + /// + /// - Returns: `Polynomial` + /// + /// - Throws: `RuntimeError`, indicates invalid `ThresholdKey`. public func reconstruct_latest_poly() throws -> Polynomial { var errorCode: Int32 = -1 let curvePointer = UnsafeMutablePointer(mutating: (curveN as NSString).utf8String) @@ -174,10 +187,11 @@ public class ThresholdKey { return Polynomial(pointer: result!) } - /** - This function returns all of the share stores that were used to generate the latest polynomial as a ShareStoreArray object. It throws an error if an error occurs while retrieving the share stores. - */ - + /// Returns share stores for the latest polynomial. + /// + /// - Returns: `ShareStoreArray` + /// + /// - Throws: `RuntimeError`, indicates invalid `ThresholdKey`. public func get_all_share_stores_for_latest_polynomial() throws -> ShareStoreArray { var errorCode: Int32 = -1 @@ -188,7 +202,7 @@ public class ThresholdKey { guard errorCode == 0 else { throw RuntimeError("Error in ThresholdKey get_all_share_stores_for_latest_polynomial") } - return try! ShareStoreArray.init(pointer: result!); + return ShareStoreArray.init(pointer: result!); } @@ -212,9 +226,11 @@ public class ThresholdKey { } } - /** - This is an asynchronous function that generates new share for given tkey. It throws an error if an error occurs during share generation or if the function is cancelled. - */ + /// Generates a new share. + /// + /// - Returns: `GenerateShareStoreArray` + /// + /// - Throws: `RuntimeError`, indicates invalid `ThresholdKey`. public func generate_new_share() async throws -> GenerateShareStoreResult { return try await withCheckedThrowingContinuation { continuation in self.generate_new_share() { @@ -248,9 +264,9 @@ public class ThresholdKey { } } - /** - This is an async function deletes a specific share store using its index. - */ + /// Deletes a share at the specified index. Caution is advised to not try delete a share that would prevent the total number of shares being below the threshold. + /// + /// - Throws: `RuntimeError`, indicates invalid share index or invalid `ThresholdKey`. public func delete_share(share_index: String) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -284,9 +300,9 @@ public class ThresholdKey { } } - /** - This function deletes the threshold key. Be careful to use this function since this operation can't be roll backed. - */ + /// Permanently deletes a tKey, this process is irrecoverable. + /// + /// - Throws: `RuntimeError`, indicates invalid `ThresholdKey`. public func CRITICAL_delete_tkey() async throws { return try await withCheckedThrowingContinuation { continuation in @@ -302,11 +318,11 @@ public class ThresholdKey { } } - /** - Returns the details of the threshold key. - - Throws: `RuntimeError` if there was an error in Threshold while getting key details. - - Returns: A `KeyDetails` object containing key details. - */ + /// Returns the key details, mainly used after reconstruction. + /// + /// - Returns: `KeyDetails` + /// + /// - Throws: `RuntimeError`, indicates invalid `ThresholdKey`. public func get_key_details() throws -> KeyDetails { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, {error in @@ -318,13 +334,16 @@ public class ThresholdKey { return try! KeyDetails(pointer: result!) } - /// Outputs a share for the given share index and share type. + /// Retrieves a specific share. + /// /// - Parameters: /// - shareIndex: The index of the share to output. - /// - shareType: The type of the share to output, or `nil` to output all shares. - /// - Throws: `RuntimeError` if there was an error in ThresholdKey output_share. - /// - Returns: The output share as a string. - public func output_share( shareIndex: String, shareType: String? = nil) throws -> String { + /// - shareType: The format of the output, can be `"mnemonic"`, optional. + + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. + public func output_share(shareIndex: String, shareType: String? = nil) throws -> String { var errorCode: Int32 = -1 let curvePointer = UnsafeMutablePointer(mutating: (curveN as NSString).utf8String) let cShareIndex = UnsafeMutablePointer(mutating: (shareIndex as NSString).utf8String) @@ -345,6 +364,14 @@ public class ThresholdKey { return string } + /// Converts a share to a `ShareStore`. + /// + /// - Parameters: + /// - share: Hexadecimal representation of a share as `String`. + + /// - Returns: `ShareStore` + /// + /// - Throws: `RuntimeError`, indicates invalid parameter. public func share_to_share_store(share: String) throws -> ShareStore { var errorCode: Int32 = -1 let curvePointer = UnsafeMutablePointer(mutating: (curveN as NSString).utf8String) @@ -359,7 +386,7 @@ public class ThresholdKey { return ShareStore.init(pointer: result!) } - private func input_share( share: String, shareType: String?, completion: @escaping (Result) -> Void) { + private func input_share(share: String, shareType: String?, completion: @escaping (Result) -> Void) { tkeyQueue.async { do { var errorCode: Int32 = -1 @@ -383,6 +410,13 @@ public class ThresholdKey { } } + /// Inserts a share into `ThresholdKey`, this is used prior to reconstruction in order to ensure the number of shares meet the threshold. + /// + /// - Parameters: + /// - share: Hex representation of a share as `String`. + /// - shareType: The format of the share, can be `"mnemonic"`, optional. + /// + /// - Throws: `RuntimeError`, indicates invalid parameter of invalid `ThresholdKey`. public func input_share(share: String, shareType: String?) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -398,6 +432,15 @@ public class ThresholdKey { } } + /// Retrieves a specific `ShareStore`. + /// + /// - Parameters: + /// - shareIndex: The index of the share to output. + /// - polyID: The polynomial id to be used for the output, optional + + /// - Returns: `ShareStore` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func output_share_store( shareIndex: String, polyId: String?) throws -> ShareStore { var errorCode: Int32 = -1 let curvePointer = UnsafeMutablePointer(mutating: (curveN as NSString).utf8String) @@ -433,6 +476,12 @@ public class ThresholdKey { } } + /// Inserts a `ShareStore` into `ThresholdKey`, useful for insertion before reconstruction to ensure the number of shares meet the minimum threshold. + /// + /// - Parameters: + /// - shareStore: The `ShareStore` to be inserted + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func input_share_store(shareStore: ShareStore) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -448,6 +497,11 @@ public class ThresholdKey { } } + /// Retrieves all share indexes for a `ThresholdKey`. + /// + /// - Returns: Array of `String` + /// + /// - Throws: `RuntimeError`, indicates invalid `ThresholdKey`. public func get_shares_indexes() throws -> [String] { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, {error in @@ -463,6 +517,11 @@ public class ThresholdKey { return indexes } + /// Encrypts a message. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func encrypt(msg: String) throws -> String { var errorCode: Int32 = -1 let curvePointer = UnsafeMutablePointer(mutating: (curveN as NSString).utf8String) @@ -479,6 +538,11 @@ public class ThresholdKey { return string } + /// Decrypts a message. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func decrypt(msg: String) throws -> String { var errorCode: Int32 = -1 let msgPointer = UnsafeMutablePointer(mutating: (msg as NSString).utf8String) @@ -494,6 +558,11 @@ public class ThresholdKey { return string } + /// Returns last metadata fetched from the cloud. + /// + /// - Returns: `Metadata` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func get_last_fetched_cloud_metadata() throws -> Metadata { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in threshold_key_get_last_fetched_cloud_metadata(pointer, error)}) @@ -503,7 +572,12 @@ public class ThresholdKey { return Metadata.init(pointer: result) } - public func get_local_metadata_transitions() throws ->LocalMetadataTransitions { + /// Returns current metadata transitions not yet synchronised. + /// + /// - Returns: `LocalMetadataTransitions` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. + public func get_local_metadata_transitions() throws -> LocalMetadataTransitions { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in threshold_key_get_local_metadata_transitions(pointer, error)}) guard errorCode == 0 else { @@ -512,6 +586,14 @@ public class ThresholdKey { return LocalMetadataTransitions.init(pointer: result!) } + /// Returns the tKey store for a module. + /// + /// - Parameters: + /// - moduleName: Specific name of the module. + /// + /// - Returns: Array of objects. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func get_tkey_store(moduleName: String) throws -> [[String:Any]] { var errorCode: Int32 = -1 @@ -531,6 +613,15 @@ public class ThresholdKey { return jsonArray } + /// Returns the specific tKey store item json for a module. + /// + /// - Parameters: + /// - moduleName: Specific name of the module. + /// - id: Identifier of the item. + /// + /// - Returns: `String` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func get_tkey_store_item(moduleName: String, id: String) throws -> [String:Any] { var errorCode: Int32 = -1 let modulePointer = UnsafeMutablePointer(mutating: (moduleName as NSString).utf8String) @@ -550,7 +641,11 @@ public class ThresholdKey { return json } - + /// Returns all shares according to their mapping. + /// + /// - Returns: `ShareStorePolyIdIndexMap` + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func get_shares() throws -> ShareStorePolyIdIndexMap { var errorCode: Int32 = -1 @@ -583,6 +678,9 @@ public class ThresholdKey { } } + /// Syncronises metadata transitions, only used if manual sync is enabled. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func sync_local_metadata_transistions() async throws { return try await withCheckedThrowingContinuation { continuation in @@ -597,7 +695,12 @@ public class ThresholdKey { } } } - + + /// Returns all shares descriptions. + /// + /// - Returns: Array of objects. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func get_share_descriptions() throws -> [String: [String]] { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in @@ -625,7 +728,7 @@ public class ThresholdKey { withUnsafeMutablePointer(to: &errorCode, { error in threshold_key_add_share_description(self.pointer, keyPointer, descriptionPointer, update_metadata, curvePointer, error)}) guard errorCode == 0 else { - throw RuntimeError("Error in ThresholdKey Reconstruct") + throw RuntimeError("Error in ThresholdKey add_share_description") } completion(.success(())) } catch { @@ -634,6 +737,14 @@ public class ThresholdKey { } } + /// Adds a share description. + /// + /// - Parameters: + /// - key: The key, usually the share index. + /// - description: Description for the key. + /// - update_metadata: Whether the metadata is synced immediately or not. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func add_share_description(key: String, description: String, update_metadata: Bool = true) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -660,7 +771,7 @@ public class ThresholdKey { withUnsafeMutablePointer(to: &errorCode, { error in threshold_key_update_share_description(self.pointer, keyPointer, oldDescriptionPointer, newDescriptionPointer, update_metadata, curvePointer, error)}) guard errorCode == 0 else { - throw RuntimeError("Error in ThresholdKey Reconstruct") + throw RuntimeError("Error in ThresholdKey update_share_description") } completion(.success(())) } catch { @@ -669,6 +780,15 @@ public class ThresholdKey { } } + /// Updates a share description. + /// + /// - Parameters: + /// - key: The relevant key. + /// - oldDescription: Old description used for the key + /// - newDescription: New description for the key. + /// - update_metadata: Whether the metadata is synced immediately or not. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func update_share_description(key: String, oldDescription: String, newDescription: String, update_metadata: Bool = true) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -694,7 +814,7 @@ public class ThresholdKey { withUnsafeMutablePointer(to: &errorCode, { error in threshold_key_delete_share_description(self.pointer, keyPointer, descriptionPointer, update_metadata, curvePointer, error)}) guard errorCode == 0 else { - throw RuntimeError("Error in ThresholdKey Reconstruct") + throw RuntimeError("Error in ThresholdKey delete_share_description") } completion(.success(())) } catch { @@ -703,6 +823,14 @@ public class ThresholdKey { } } + /// Deletes a share description. + /// + /// - Parameters: + /// - key: The relevant key. + /// - description: Current description for the key. + /// - update_metadata: Whether the metadata is synced immediately or not. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func delete_share_description(key: String, description: String, update_metadata: Bool = true) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -739,6 +867,12 @@ public class ThresholdKey { } } + /// Function to retrieve the metadata directly from the network, only used in very specific instances. + /// + /// - Parameters: + /// - private_key: The reconstructed key, optional. + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func storage_layer_get_metadata(private_key: String?) async throws -> String { return try await withCheckedThrowingContinuation { continuation in @@ -775,6 +909,13 @@ public class ThresholdKey { } } + /// Function to set the metadata directly to the network, only used for specific instances. + /// + /// - Parameters: + /// - private_key: The reconstructed key. + /// - json: Relevant json to be set + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func storage_layer_set_metadata(private_key: String?, json: String) async throws { return try await withCheckedThrowingContinuation { continuation in @@ -808,6 +949,13 @@ public class ThresholdKey { } } + /// Function to set the metadata directly to the network, only used for specific instances. + /// + /// - Parameters: + /// - private_keys: The relevant private keys. + /// - json: Relevant json to be set + /// + /// - Throws: `RuntimeError`, indicates invalid parameters or invalid `ThresholdKey`. public func storage_layer_set_metadata_stream(private_keys: String, json: String) async throws { return try await withCheckedThrowingContinuation { continuation in diff --git a/Sources/ThresholdKey/Version.swift b/Sources/ThresholdKey/Version.swift index 6008e36..754415b 100644 --- a/Sources/ThresholdKey/Version.swift +++ b/Sources/ThresholdKey/Version.swift @@ -1,15 +1,13 @@ -// -// Version.swift -// tkey_ios -// -// Created by CW Lee on 17/11/2022. -// - import Foundation #if canImport(lib) import lib #endif +/// Returns the library version. +/// +/// - Returns: `String`. +/// +/// - Throws: `RuntimeError`, underlying library problem. public func library_version() throws -> String { var errorCode: Int32 = -1 let result = withUnsafeMutablePointer(to: &errorCode, { error in diff --git a/Tests/tkeypkgTests/tkey_pkgThresholdKeyTests.swift b/Tests/tkeypkgTests/tkey_pkgThresholdKeyTests.swift index 525a6a4..1dd4215 100644 --- a/Tests/tkeypkgTests/tkey_pkgThresholdKeyTests.swift +++ b/Tests/tkeypkgTests/tkey_pkgThresholdKeyTests.swift @@ -12,7 +12,6 @@ final class tkey_pkgThresholdKeyTests: XCTestCase { service_provider: service_provider, enable_logging: true, manual_sync: false) - let key = try! PrivateKey.generate() _ = try! await threshold_key.initialize() _ = try! await threshold_key.reconstruct() } @@ -26,7 +25,6 @@ final class tkey_pkgThresholdKeyTests: XCTestCase { service_provider: service_provider, enable_logging: true, manual_sync: false) - let key = try! PrivateKey.generate() _ = try! await threshold_key.initialize() _ = try! await threshold_key.reconstruct() _ = try! threshold_key.get_key_details() @@ -60,7 +58,6 @@ final class tkey_pkgThresholdKeyTests: XCTestCase { service_provider: service_provider, enable_logging: true, manual_sync: true) - let key = try! PrivateKey.generate() _ = try! await threshold_key.initialize() _ = try! await threshold_key.reconstruct() _ = try! await threshold_key.generate_new_share() @@ -124,10 +121,8 @@ final class tkey_pkgThresholdKeyTests: XCTestCase { service_provider: service_provider2, enable_logging: true, manual_sync: false) - let key = try! PrivateKey.generate() _ = try! await threshold_key.initialize() let reconstruct1 = try! await threshold_key.reconstruct() - let key2 = try! PrivateKey.generate() _ = try! await threshold_key2.initialize() let reconstruct2 = try! await threshold_key2.reconstruct() XCTAssertNotEqual(reconstruct1.key, reconstruct2.key)