Skip to content

Commit

Permalink
implement getOrSetSapphireMetadataNonce
Browse files Browse the repository at this point in the history
  • Loading branch information
metalurgical committed May 16, 2024
1 parent 1cc5cbf commit e1e5f66
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 51 deletions.
8 changes: 8 additions & 0 deletions Sources/TorusUtils/Helpers/MetadataUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,12 @@ internal class MetadataUtils {
public static func getNonce(legacyMetadataHost: String, serverTimeOffset: Int, X: String, Y: String, privateKey: String? = nil, getOnly: Bool = false) async throws -> GetOrSetNonceResult {
return try await getOrSetNonce(legacyMetadataHost: legacyMetadataHost, serverTimeOffset: serverTimeOffset, X: X, Y: Y, privateKey: privateKey, getOnly: true)
}

public static func getOrSetSapphireMetadataNonce(legacyMetadataHost: String, network: TorusNetwork, X: String, Y: String, serverTimeOffset: Int, privateKey: String? = nil, getOnly: Bool = false) async throws -> GetOrSetNonceResult {
if case .sapphire = network {
return try await getOrSetNonce(legacyMetadataHost: legacyMetadataHost, serverTimeOffset: serverTimeOffset, X: X, Y: Y)
} else {
throw TorusUtilError.metadataNonceMissing
}
}
}
83 changes: 49 additions & 34 deletions Sources/TorusUtils/Helpers/NodeUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal class NodeUtils {
network: TorusNetwork,
verifier: String,
verifierId: String,
legacyMetadataHost: String,
extendedVerifierId: String? = nil) async throws -> KeyLookupResult {
let threshold = Int(trunc(Double((endpoints.count / 2) + 1)))

Expand All @@ -27,8 +28,8 @@ internal class NodeUtils {
var nonceResult: GetOrSetNonceResult?
var nodeIndexes: [Int] = []

let minRequired = Int(trunc(Double((endpoints.count * 3 / 4))+1))
let minRequired = Int(trunc(Double(endpoints.count * 3 / 4) + 1))

let lookupResults: [JRPCResponse<VerifierLookupResponse>?] = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: [JRPCResponse<VerifierLookupResponse>?].self) { group -> [JRPCResponse?] in
var received: Int = 0
for endpoint in endpoints {
Expand Down Expand Up @@ -65,15 +66,14 @@ internal class NodeUtils {

let keyResult = try thresholdSame(arr: normalizedKeyResults, threshold: threshold)

// Note: The condition for nonceResult will always pass as it was never assigned
if keyResult != nil && nonceResult == nil && extendedVerifierId == nil && !TorusUtils.isLegacyNetworkRouteMap(network: network) {
for i in 0 ..< lookupResults.count {
let x1 = lookupResults[i]
if x1 != nil && x1?.error == nil {
let currentNodePubKey = x1!.result!.keys[0].pub_key_X.lowercased()
let thresholdPubKey = keyResult!.keys[0].pub_key_X.lowercased()
let pubNonceX: String? = x1!.result!.keys[0].nonce_data?.pubNonce?.x
if pubNonceX != nil && currentNodePubKey == thresholdPubKey {
let currentNodePubKeyX = x1!.result!.keys[0].pub_key_X.addLeading0sForLength64().lowercased()
let thresholdPubKeyX = keyResult!.keys[0].pub_key_X.addLeading0sForLength64().lowercased()
let pubNonce: PubNonce? = x1!.result!.keys[0].nonce_data?.pubNonce
if pubNonce != nil && currentNodePubKeyX == thresholdPubKeyX {
nonceResult = x1?.result?.keys[0].nonce_data
break
}
Expand Down Expand Up @@ -101,6 +101,16 @@ internal class NodeUtils {
}

let serverTimeOffset = (keyResult != nil) ? calculateMedian(arr: serverTimeOffsets) : 0

if case .sapphire = network {
let X: BigInt = BigInt(nonceResult?.pubNonce?.x ?? "0", radix: 16) ?? BigInt(0)
let Y: BigInt = BigInt(nonceResult?.pubNonce?.x ?? "0", radix: 16) ?? BigInt(0)
if nonceResult == nil || (X == BigInt(0) && Y == BigInt(0)) {
let metadataNonce = try await MetadataUtils.getOrSetSapphireMetadataNonce(legacyMetadataHost: legacyMetadataHost, network: network, X: keyResult!.keys[0].pub_key_X, Y: keyResult!.keys[0].pub_key_Y, serverTimeOffset: serverTimeOffset, getOnly: false)
nonceResult = metadataNonce
}
}

return KeyLookupResult(
keyResult: keyResult,
nodeIndexes: nodeIndexes,
Expand Down Expand Up @@ -168,8 +178,8 @@ internal class NodeUtils {
encoder.outputFormatting = .sortedKeys
let rpcdata = try encoder.encode(jsonRPCRequest)

let minRequired = Int(trunc(Double((endpoints.count * 3 / 4))+1))
let minRequired = Int(trunc(Double(endpoints.count * 3 / 4) + 1))

let commitmentRequestResults: [JRPCResponse<CommitmentRequestResult>?] = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: [JRPCResponse<CommitmentRequestResult>?].self) { group -> [JRPCResponse?] in
var received: Int = 0
for endpoint in endpoints {
Expand Down Expand Up @@ -200,10 +210,6 @@ internal class NodeUtils {

let completedCommitmentRequests = commitmentRequestResults.filter({ $0 != nil && $0?.error == nil })

// Invert first comparision in corresponding javascript to return error case early
// Comment: Refactor javascript to not chain and embed promises within promises
// as extensively as it has been currently implemented

if importedShareCount > 0 && !(commitmentRequestResults.count == endpoints.count) {
throw TorusUtilError.commitmentRequestFailed
}
Expand Down Expand Up @@ -327,18 +333,34 @@ internal class NodeUtils {
}

for item in shareResponses {
// first check will always pass as it is never assigned
if thresholdNonceData == nil && verifierParams.extended_verifier_id == nil {
let currentPubKey = item.keys[0].publicKey
let pubNonce = item.keys[0].nonceData?.pubNonce?.x
if pubNonce != nil && currentPubKey.X == thresholdPublicKey!.X {
let currentPubKeyX = item.keys[0].publicKey.X.addLeading0sForLength64().lowercased()
let thesholdPubKeyX = thresholdPublicKey!.X.addLeading0sForLength64().lowercased()
let pubNonce: PubNonce? = item.keys[0].nonceData?.pubNonce
if pubNonce != nil && currentPubKeyX == thesholdPubKeyX {
thresholdNonceData = item.keys[0].nonceData
}
}
}

var serverTimeOffsets: [String] = []
for item in shareResponses {
serverTimeOffsets.append(item.serverTimeOffset)
}
let serverOffsetTimes = serverTimeOffsets.map({ Int($0) ?? 0 })

if thresholdNonceData == nil && verifierParams.extended_verifier_id == nil && !TorusUtils.isLegacyNetworkRouteMap(network: network) {
throw TorusUtilError.runtime("invalid metadata result from nodes, nonce metadata is empty")
let serverTimeOffsetResponse: Int = serverTimeOffset ?? calculateMedian(arr: serverOffsetTimes)

let nX: BigInt = BigInt(thresholdNonceData?.pubNonce?.x ?? "0", radix: 16) ?? BigInt(0)
let nY: BigInt = BigInt(thresholdNonceData?.pubNonce?.x ?? "0", radix: 16) ?? BigInt(0)

if (thresholdNonceData == nil || (nX == BigInt(0) && nY == BigInt(0))) && verifierParams.extended_verifier_id == nil && !TorusUtils.isLegacyNetworkRouteMap(network: network) {
if case .sapphire = network {
let metadataNonce = try await MetadataUtils.getOrSetSapphireMetadataNonce(legacyMetadataHost: legacyMetadataHost, network: network, X: thresholdPublicKey!.X, Y: thresholdPublicKey!.Y, serverTimeOffset: serverTimeOffsetResponse, getOnly: false)
thresholdNonceData = metadataNonce
} else {
throw TorusUtilError.runtime("invalid metadata result from nodes, nonce metadata is empty")
}
}

let thresholdReqCount = (importedShares != nil && importedShares!.count > 0) ? endpoints.count : threshold
Expand All @@ -354,11 +376,9 @@ internal class NodeUtils {
var nodeIndexes: [Int?] = []
var sessionTokenDatas: [SessionToken?] = []
var isNewKeys: [String] = []
var serverTimeOffsets: [String] = []

for item in shareResponses {
isNewKeys.append(item.isNewKey)
serverTimeOffsets.append(item.serverTimeOffset)

if !item.sessionTokenSigs.isEmpty {
if !item.sessionTokenSigMetadata.isEmpty {
Expand Down Expand Up @@ -457,14 +477,10 @@ internal class NodeUtils {

let thresholdIsNewKey = try thresholdSame(arr: isNewKeys, threshold: threshold)

let serverOffsetTimes = serverTimeOffsets.map({ Int($0) ?? 0 })

let serverTimeOffsetResponse: Int = serverTimeOffset ?? calculateMedian(arr: serverOffsetTimes)

let oAuthKey = privateKey!.addLeading0sForLength64()
let oAuthPublicKey = try SecretKey(hex: oAuthKey).toPublic().serialize(compressed: false)
let (oAuthPublicKeyX, oAuthPublicKeyY) = try KeyUtils.getPublicKeyCoords(pubKey: oAuthPublicKey)
var metadataNonce = BigInt(thresholdNonceData?.nonce?.addLeading0sForLength64() ?? "0", radix: 16)
var metadataNonce = BigInt(thresholdNonceData?.nonce?.addLeading0sForLength64() ?? "0", radix: 16) ?? BigInt(0)
var finalPubKey: String?
var pubNonce: PubNonce?
var typeOfUser: UserType = .v1
Expand All @@ -474,7 +490,7 @@ internal class NodeUtils {
} else if TorusUtils.isLegacyNetworkRouteMap(network: network) {
if enableOneKey {
let nonce = try await MetadataUtils.getOrSetNonce(legacyMetadataHost: legacyMetadataHost, serverTimeOffset: serverTimeOffsetResponse, X: oAuthPublicKeyX, Y: oAuthPublicKeyY, getOnly: !(Bool(thresholdIsNewKey ?? "true")!))
metadataNonce = BigInt(nonce.nonce?.addLeading0sForLength64() ?? "0", radix: 16)
metadataNonce = BigInt(nonce.nonce?.addLeading0sForLength64() ?? "0", radix: 16) ?? BigInt(0)
typeOfUser = UserType(rawValue: nonce.typeOfUser?.lowercased() ?? "v1")!
if typeOfUser == .v2 {
pubNonce = nonce.pubNonce
Expand All @@ -483,17 +499,16 @@ internal class NodeUtils {
} else {
typeOfUser = .v1
metadataNonce = BigInt(try await MetadataUtils.getMetadata(legacyMetadataHost: legacyMetadataHost, dictionary: ["pub_key_X": oAuthPublicKeyX, "pub_key_Y": oAuthPublicKeyY]))
let privateKeyWithNonce = (BigInt(oAuthKey, radix: 16)! + BigInt(metadataNonce!)).modulus(KeyUtils.getOrderOfCurve())
let privateKeyWithNonce = (BigInt(oAuthKey, radix: 16)! + BigInt(metadataNonce)).modulus(KeyUtils.getOrderOfCurve())
finalPubKey = try SecretKey(hex: privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64()).toPublic().serialize(compressed: false)
}
} else {
typeOfUser = .v1
metadataNonce = BigInt(try await MetadataUtils.getMetadata(legacyMetadataHost: legacyMetadataHost, dictionary: ["pub_key_X": oAuthPublicKeyX, "pub_key_Y": oAuthPublicKeyY]))
let privateKeyWithNonce = (BigInt(oAuthKey, radix: 16)! + BigInt(metadataNonce!)).modulus(KeyUtils.getOrderOfCurve())
let privateKeyWithNonce = (BigInt(oAuthKey, radix: 16)! + BigInt(metadataNonce)).modulus(KeyUtils.getOrderOfCurve())
finalPubKey = try SecretKey(hex: privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64()).toPublic().serialize(compressed: false)
}
} else {
// TODO: BUG: Nonce is returned as (x=0,y=0) sometimes, this is invalid investigate further
typeOfUser = .v2
let publicNonce = KeyUtils.getPublicKeyFromCoords(pubKeyX: thresholdNonceData!.pubNonce!.x, pubKeyY: thresholdNonceData!.pubNonce!.y)
let oAuthPubKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: oAuthPublicKeyX, pubKeyY: oAuthPublicKeyY)
Expand All @@ -511,14 +526,14 @@ internal class NodeUtils {
let finalEvmAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: finalPubX, publicKeyY: finalPubY)

var finalPrivKey = ""
if typeOfUser == .v1 || (typeOfUser == .v2 && metadataNonce! > BigInt(0)) {
let privateKeyWithNonce = ((BigInt(oAuthKey, radix: 16) ?? BigInt(0)) + metadataNonce!).modulus(KeyUtils.getOrderOfCurve())
if typeOfUser == .v1 || (typeOfUser == .v2 && metadataNonce > BigInt(0)) {
let privateKeyWithNonce = ((BigInt(oAuthKey, radix: 16) ?? BigInt(0)) + metadataNonce).modulus(KeyUtils.getOrderOfCurve())
finalPrivKey = privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64()
}

var isUpgraded: Bool?
if typeOfUser == .v2 {
isUpgraded = metadataNonce! == BigInt(0)
isUpgraded = metadataNonce == BigInt(0)
}

return TorusKey(
Expand All @@ -537,7 +552,7 @@ internal class NodeUtils {
sessionAuthKey: sessionAuthKeySerialized),
metadata: TorusPublicKey.Metadata(
pubNonce: pubNonce,
nonce: metadataNonce?.magnitude,
nonce: metadataNonce.magnitude,
typeOfUser: typeOfUser,
upgraded: isUpgraded,
serverTimeOffset: serverTimeOffsetResponse),
Expand Down
2 changes: 1 addition & 1 deletion Sources/TorusUtils/Interfaces/TorusOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class TorusOptions {
/// - enableOneKey: Use the oneKey flow.
///
/// - Returns: `TorusOptions`
public init(clientId: String, network: TorusNetwork, legacyMetadataHost: String = "https://metadata.tor.us", serverTimeOffset: Int = 0, enableOneKey: Bool = false) {
public init(clientId: String, network: TorusNetwork, legacyMetadataHost: String? = nil, serverTimeOffset: Int = 0, enableOneKey: Bool = false) {
self.clientId = clientId
self.enableOneKey = enableOneKey
self.network = network
Expand Down
23 changes: 17 additions & 6 deletions Sources/TorusUtils/TorusUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,24 @@ public class TorusUtils {
/// - logLevel: `OSLogType`, only needs to be provided if the default logging level should be changed
///
/// - Returns: `TorusUtils`
public init(params: TorusOptions, loglevel: OSLogType = .default) {
///
/// - Throws: `TorusUtilError.invalidInput`
public init(params: TorusOptions, loglevel: OSLogType = .default) throws {
var defaultHost = ""
if params.legacyMetadataHost == nil {
if case let .legacy(urlHost) = params.network {
defaultHost = urlHost.metadataMap
} else {
defaultHost = (LegacyNetwork.MAINNET.metadataMap)
// TODO: Move this into fetchNodeDetails metadataMap
if case let .sapphire(sapphireNetwork) = params.network {
if sapphireNetwork == .SAPPHIRE_MAINNET {
defaultHost = "https://node-1.node.web3auth.io/metadata"
} else {
defaultHost = "https://node-1.dev-node.web3auth.io/metadata"
}
} else {
throw TorusUtilError.invalidInput
}
}
} else {
defaultHost = params.legacyMetadataHost!
Expand Down Expand Up @@ -208,7 +219,8 @@ public class TorusUtils {
throw TorusUtilError.runtime("Missing node pub key for node index")
}
let shareJson = try encoder.encode(share)
enc.append(try MetadataUtils.encrypt(publicKey: KeyUtils.getPublicKeyFromCoords(pubKeyX: nodePubs[i].X, pubKeyY: nodePubs[i].Y), msg: share!.share.magnitude.serialize().hexString.addLeading0sForLength64()))
let encPubKey = try PublicKey(hex: KeyUtils.getPublicKeyFromCoords(pubKeyX: nodePubs[i].X, pubKeyY: nodePubs[i].Y))
enc.append(try MetadataUtils.encrypt(publicKey: encPubKey.serialize(compressed: true), msg: share!.share.magnitude.serialize().hexString.addLeading0sForLength64()))
jsonShares.append(shareJson)
}

Expand Down Expand Up @@ -276,7 +288,7 @@ public class TorusUtils {
}

private func getNewPublicAddress(endpoints: [String], verifier: String, verifierId: String, extendedVerifierId: String? = nil, enableOneKey: Bool) async throws -> TorusPublicKey {
let keyAssignResult = try await NodeUtils.getPubKeyOrKeyAssign(endpoints: endpoints, network: network, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId)
let keyAssignResult = try await NodeUtils.getPubKeyOrKeyAssign(endpoints: endpoints, network: network, verifier: verifier, verifierId: verifierId, legacyMetadataHost: legacyMetadataHost, extendedVerifierId: extendedVerifierId)

if keyAssignResult.errorResult != nil {
let error = keyAssignResult.errorResult!.message
Expand All @@ -298,7 +310,7 @@ public class TorusUtils {
let pubKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: keyAssignResult.keyResult!.keys[0].pub_key_X, pubKeyY: keyAssignResult.keyResult!.keys[0].pub_key_Y)

var pubNonce: PubNonce?
let nonce: BigUInt = BigUInt(keyAssignResult.nonceResult?.nonce ?? "0", radix: 16)!
let nonce: BigUInt = BigUInt(keyAssignResult.nonceResult?.nonce ?? "0", radix: 16) ?? BigUInt(0)

var oAuthPubKey: String?
var finalPubKey: String?
Expand All @@ -315,7 +327,6 @@ public class TorusUtils {
let legacyResult = LegacyVerifierLookupResponse(keys: legacyKeysResult, serverTimeOffset: String(finalServerTimeOffset))
return try await formatLegacyPublicKeyData(finalKeyResult: legacyResult, enableOneKey: enableOneKey, isNewKey: keyAssignResult.keyResult!.is_new_key, serverTimeOffset: finalServerTimeOffset)
} else {
// TODO: BUG: Nonce is returned as (x=0,y=0) sometimes, this is invalid investigate further
let pubNonceResult = keyAssignResult.nonceResult!.pubNonce!
oAuthPubKey = pubKey
let pubNonceKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: pubNonceResult.x, pubKeyY: pubNonceResult.y)
Expand Down
2 changes: 1 addition & 1 deletion Tests/TorusUtilsTests/AquaTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class AquaTest: XCTestCase {
override func setUp() {
super.setUp()
fnd = NodeDetailManager(network: .legacy(.AQUA))
torus = TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.AQUA)))
torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.AQUA)))
}

func test_should_fetch_public_address() async throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/TorusUtilsTests/Celeste.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CelesteTest: XCTestCase {
override func setUp() {
super.setUp()
fnd = NodeDetailManager(network: .legacy(.CELESTE))
torus = TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.CELESTE)))
torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.CELESTE)))
}

func test_should_fetch_public_address() async throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/TorusUtilsTests/CyanTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CyanTest: XCTestCase {
override func setUp() {
super.setUp()
fnd = NodeDetailManager(network: .legacy(.CYAN))
torus = TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.CYAN)))
torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.CYAN)))
}

func test_should_fetch_public_address() async throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/TorusUtilsTests/MainnetTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class MainnetTests: XCTestCase {
override func setUp() {
super.setUp()
fnd = NodeDetailManager(network: .legacy(.MAINNET))
torus = TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.MAINNET)))
torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.MAINNET)))
}

func test_should_fetch_public_address() async throws {
Expand Down
2 changes: 1 addition & 1 deletion Tests/TorusUtilsTests/SapphireDevnetTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class SapphireDevnetTest: XCTestCase {
override func setUp() {
super.setUp()
fnd = NodeDetailManager(network: .sapphire(.SAPPHIRE_DEVNET))
torus = TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .sapphire(.SAPPHIRE_DEVNET)))
torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .sapphire(.SAPPHIRE_DEVNET)))
}

func test_should_fetch_public_address() async throws {
Expand Down
Loading

0 comments on commit e1e5f66

Please sign in to comment.