Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 73 additions & 77 deletions Sources/tss-client-swift/Helpers.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import BigInt
import Foundation
import CryptoKit
import Foundation

public class TSSHelpers {
// singleton class
Expand All @@ -14,7 +14,7 @@ public class TSSHelpers {
/// - Returns: `String`
public static func hashMessage(message: String) -> String {
let hash = Data(message.utf8).sha3(.keccak256)
return hash.hexString
return hash.base64EncodedString()
}

/// Converts a share to base64
Expand Down Expand Up @@ -69,7 +69,12 @@ public class TSSHelpers {
public static func recoverPublicKey(msgHash: String, s: BigInt, r: BigInt, v: UInt8) throws -> Data {
if let secpSigMarshalled = SECP256K1.marshalSignature(v: v, r: r.serialize().suffix(32), s: s.serialize().suffix(32))
{
if let pk = SECP256K1.recoverPublicKey(hash: Data(hex: msgHash), signature: secpSigMarshalled, compressed: false) {
guard let msgData = msgHash.data(using: .utf8),
let msgB64 = Data(base64Encoded: msgData)
else {
throw TSSClientError("Invalid base64 encoded hash")
}
if let pk = SECP256K1.recoverPublicKey(hash: msgB64, signature: secpSigMarshalled, compressed: false) {
return pk
} else {
throw TSSClientError("Public key recover failed")
Expand Down Expand Up @@ -167,7 +172,7 @@ public class TSSHelpers {
throw TSSClientError("Problem with signature components")
}
}

/// Calculates server coefficients based on the distributed key generation indexes and the user tss index
///
/// - Parameters:
Expand All @@ -179,17 +184,15 @@ public class TSSHelpers {
/// - Throws: `TSSClientError`
public static func getServerCoefficients(participatingServerDKGIndexes: [BigInt], userTssIndex: BigInt) throws -> [String: String] {
var serverCoeffs: [String: String] = [:]
for i in 0..<participatingServerDKGIndexes.count
{
for i in 0 ..< participatingServerDKGIndexes.count {
let coefficient = try getDKLSCoefficient(isUser: false, participatingServerIndexes: participatingServerDKGIndexes, userTssIndex: userTssIndex, serverIndex: participatingServerDKGIndexes[i])
//values should never contain leading zeros
serverCoeffs.updateValue(coefficient.serialize().suffix(32).hexString.removeLeadingZeros() ,forKey: participatingServerDKGIndexes[i].serialize().suffix(32).hexString.removeLeadingZeros())

// values should never contain leading zeros
serverCoeffs.updateValue(coefficient.serialize().suffix(32).hexString.removeLeadingZeros(), forKey: participatingServerDKGIndexes[i].serialize().suffix(32).hexString.removeLeadingZeros())
}

return serverCoeffs
}

/// Calculates the public key that will be used for TSS signing.
///
/// - Parameters:
Expand All @@ -201,42 +204,41 @@ public class TSSHelpers {
///
/// - Throws: `TSSClientError`
public static func getFinalTssPublicKey(dkgPubKey: Data, userSharePubKey: Data, userTssIndex: BigInt) throws -> Data {
let serverLagrangeCoeff = try TSSHelpers.getLagrangeCoefficient(parties: [BigInt(1), userTssIndex], party: BigInt(1))
let userLagrangeCoeff = try TSSHelpers.getLagrangeCoefficient(parties: [BigInt(1), userTssIndex], party: userTssIndex)

guard let serverTermUnprocessed = SECP256K1.parsePublicKey(serializedKey: dkgPubKey),
let userTermUnprocessed = SECP256K1.parsePublicKey(serializedKey: userSharePubKey) else {
throw TSSClientError("InvalidPublicKey")
}

var serverTerm = serverTermUnprocessed
var userTerm = userTermUnprocessed
let serverLagrangeCoeff = try TSSHelpers.getLagrangeCoefficient(parties: [BigInt(1), userTssIndex], party: BigInt(1))
let userLagrangeCoeff = try TSSHelpers.getLagrangeCoefficient(parties: [BigInt(1), userTssIndex], party: userTssIndex)

guard let serverTermUnprocessed = SECP256K1.parsePublicKey(serializedKey: dkgPubKey),
let userTermUnprocessed = SECP256K1.parsePublicKey(serializedKey: userSharePubKey) else {
throw TSSClientError("InvalidPublicKey")
}

let serverLagrangeCoeffData = try Data.ensureDataLengthIs32Bytes(serverLagrangeCoeff.serialize())
let userLagrangeCoeffData = try Data.ensureDataLengthIs32Bytes(userLagrangeCoeff.serialize())
var serverTerm = serverTermUnprocessed
var userTerm = userTermUnprocessed

guard let serverTermProcessed = SECP256K1.ecdh(pubKey: serverTerm, privateKey: serverLagrangeCoeffData),
let userTermProcessed = SECP256K1.ecdh(pubKey: userTerm, privateKey: userLagrangeCoeffData) else {
throw TSSClientError("Failed to process server term")
}
let serverLagrangeCoeffData = try Data.ensureDataLengthIs32Bytes(serverLagrangeCoeff.serialize())
let userLagrangeCoeffData = try Data.ensureDataLengthIs32Bytes(userLagrangeCoeff.serialize())

serverTerm = serverTermProcessed
userTerm = userTermProcessed
guard let serverTermProcessed = SECP256K1.ecdh(pubKey: serverTerm, privateKey: serverLagrangeCoeffData),
let userTermProcessed = SECP256K1.ecdh(pubKey: userTerm, privateKey: userLagrangeCoeffData) else {
throw TSSClientError("Failed to process server term")
}

guard let serializedServerTerm = SECP256K1.serializePublicKey(publicKey: &serverTerm),
let serializedUserTerm = SECP256K1.serializePublicKey(publicKey: &userTerm) else {
throw TSSClientError("Failed to process client term")
}
serverTerm = serverTermProcessed
userTerm = userTermProcessed

guard let combination = SECP256K1.combineSerializedPublicKeys(keys: [serializedServerTerm, serializedUserTerm]) else {
throw TSSClientError("Failed to combine keys")
}
guard let serializedServerTerm = SECP256K1.serializePublicKey(publicKey: &serverTerm),
let serializedUserTerm = SECP256K1.serializePublicKey(publicKey: &userTerm) else {
throw TSSClientError("Failed to process client term")
}

guard let combination = SECP256K1.combineSerializedPublicKeys(keys: [serializedServerTerm, serializedUserTerm]) else {
throw TSSClientError("Failed to combine keys")
}

return combination
return combination
}

internal static func getAdditiveCoefficient(isUser: Bool, participatingServerIndexes: [BigInt], userTSSIndex: BigInt, serverIndex: BigInt?) throws -> BigInt {

internal static func getAdditiveCoefficient(isUser: Bool, participatingServerIndexes: [BigInt], userTSSIndex: BigInt, serverIndex: BigInt?) throws -> BigInt {
if isUser {
return try TSSHelpers.getLagrangeCoefficient(parties: [BigInt(1), userTSSIndex], party: userTSSIndex)
}
Expand All @@ -252,62 +254,60 @@ public class TSSHelpers {
}

internal static func getDenormalizedCoefficient(party: BigInt, parties: [BigInt]) throws -> BigInt {
if parties.firstIndex(where: {$0 == party}) == nil {
if parties.firstIndex(where: { $0 == party }) == nil {
throw TSSClientError("Party not found in parties")
}

let denormalizedCoefficient = try TSSHelpers.getLagrangeCoefficient(parties: parties, party: party)
guard let inverseDenormalizedCoefficient = denormalizedCoefficient.inverse(TSSClient.modulusValueSigned) else {
throw TSSClientError("Cannot calculate inverse of denormalizedCoefficient")
}

return inverseDenormalizedCoefficient.modulus(TSSClient.modulusValueSigned)
}

internal static func getDKLSCoefficient(isUser: Bool, participatingServerIndexes: [BigInt], userTssIndex: BigInt, serverIndex: BigInt?) throws -> BigInt {

let sortedServerIndexes = participatingServerIndexes.sorted()

for i in 0..<sortedServerIndexes.count {
if sortedServerIndexes[i] != participatingServerIndexes[i] {
throw TSSClientError("server indexes must be sorted")
}
}
for i in 0 ..< sortedServerIndexes.count {
if sortedServerIndexes[i] != participatingServerIndexes[i] {
throw TSSClientError("server indexes must be sorted")
}
}

var parties = [BigInt]()
var serverPartyIndex: BigInt = 0
var parties = [BigInt]()
var serverPartyIndex: BigInt = 0

for i in 0..<participatingServerIndexes.count {
let currentPartyIndex = BigInt(i + 1)
parties.append(currentPartyIndex)
if participatingServerIndexes[i] == serverIndex {
serverPartyIndex = currentPartyIndex
}
}
for i in 0 ..< participatingServerIndexes.count {
let currentPartyIndex = BigInt(i + 1)
parties.append(currentPartyIndex)
if participatingServerIndexes[i] == serverIndex {
serverPartyIndex = currentPartyIndex
}
}

let userPartyIndex = BigInt(parties.count + 1)
parties.append(userPartyIndex)
let userPartyIndex = BigInt(parties.count + 1)
parties.append(userPartyIndex)

let additiveCoeff = try TSSHelpers.getAdditiveCoefficient(isUser: isUser, participatingServerIndexes: participatingServerIndexes, userTSSIndex: userTssIndex, serverIndex: serverIndex)

if isUser {
let denormaliseCoeff = try TSSHelpers.getDenormalizedCoefficient(party: userPartyIndex, parties: parties)
return (denormaliseCoeff * additiveCoeff).modulus(TSSClient.modulusValueSigned)
} else {
let denormaliseCoeff = try TSSHelpers.getDenormalizedCoefficient(party: serverPartyIndex, parties: parties)
return (denormaliseCoeff * additiveCoeff).modulus(TSSClient.modulusValueSigned)
}
if isUser {
let denormaliseCoeff = try TSSHelpers.getDenormalizedCoefficient(party: userPartyIndex, parties: parties)
return (denormaliseCoeff * additiveCoeff).modulus(TSSClient.modulusValueSigned)
} else {
let denormaliseCoeff = try TSSHelpers.getDenormalizedCoefficient(party: serverPartyIndex, parties: parties)
return (denormaliseCoeff * additiveCoeff).modulus(TSSClient.modulusValueSigned)
}
}

internal static func getLagrangeCoefficient(parties: [BigInt], party: BigInt, _ _target: BigInt = BigInt(0)) throws -> BigInt {

internal static func getLagrangeCoefficient(parties: [BigInt], party: BigInt, _ _target: BigInt = BigInt(0)) throws -> BigInt {
let allIndexes: [BigInt] = parties
let myIndex: BigInt = party
let target: BigInt = _target
var upper = BigInt(1)
var lower = BigInt(1)
for j in 0..<allIndexes.count {

for j in 0 ..< allIndexes.count {
if myIndex != allIndexes[j] {
var tempUpper = target - allIndexes[j]
tempUpper = tempUpper.modulus(TSSClient.modulusValueSigned)
Expand All @@ -323,7 +323,7 @@ public class TSSHelpers {
throw TSSClientError("Could not calculate inverse of lower")
}
}

/// Assembles the full session string from components for signing.
///
/// - Parameters:
Expand All @@ -337,9 +337,7 @@ public class TSSHelpers {
public static func assembleFullSession(verifier: String, verifierId: String, tssTag: String, tssNonce: String, sessionNonce: String) -> String {
return verifier + Delimiters.Delimiter1 + verifierId + Delimiters.Delimiter2 + tssTag + Delimiters.Delimiter3 + tssNonce + Delimiters.Delimiter4 + sessionNonce
}




/// Generates endpoints for client based on supplied inputs.
///
/// - Parameters:
Expand All @@ -350,7 +348,6 @@ public class TSSHelpers {
///
/// - Returns: `( [String?] , [String?] , [Int], [Int] )`
public static func generateEndpoints(parties: Int, clientIndex: Int, nodeIndexes: [Int?], urls: [String]) throws -> ([String?], [String?], partyIndexes: [Int], nodeIndexes: [Int]) {

var endpoints: [String?] = []
var tssWSEndpoints: [String?] = []
var partyIndexes: [Int] = []
Expand Down Expand Up @@ -378,5 +375,4 @@ public class TSSHelpers {
}
return (endpoints, tssWSEndpoints, partyIndexes, serverIndexes)
}

}
9 changes: 1 addition & 8 deletions Sources/tss-client-swift/TSSClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -284,23 +284,16 @@ public class TSSClient {
throw TSSClientError("Insufficient Precomputes")
}

var signingMessage = ""
let signingMessage = message

if !hashOnly {
if let original_message = original_message {
if TSSHelpers.hashMessage(message: original_message) != message {
throw TSSClientError("hash of original message does not match message")
}
if let data = Data(hexString: message) {
signingMessage = data.base64EncodedString()
} else {
throw TSSClientError("Message is not a hex string")
}
} else {
throw TSSClientError("Original message has to be provided")
}
} else {
signingMessage = message
}

var fragments: [String] = []
Expand Down
4 changes: 3 additions & 1 deletion Tests/tss-client-swiftTests/tss_client_swiftTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ final class tss_client_swiftTests: XCTestCase {
var sigs: [String] = []
for item in privateKeys {
let hash = TSSHelpers.hashMessage(message: token)
let (serializedNodeSig, _) = SECP256K1.signForRecovery(hash: Data(hex: hash), privateKey: Data(hex: item))
let data = hash.data(using: .utf8)!
let msgB64 = Data(base64Encoded: data)!
let (serializedNodeSig, _) = SECP256K1.signForRecovery(hash: msgB64, privateKey: Data(hex: item))
let unmarshaled = SECP256K1.unmarshalSignature(signatureData: serializedNodeSig!)!
let sig = unmarshaled.r.hexString + unmarshaled.s.hexString + String(format: "%02X", unmarshaled.v)
let msg: [String: Any] = [
Expand Down