From 50738ac68412767c56f2589fca83cb7a13fe5276 Mon Sep 17 00:00:00 2001 From: ieow Date: Tue, 7 Jan 2025 12:27:54 +0800 Subject: [PATCH 1/7] feat: support keyType input for getPublicAddress --- src/torus.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/torus.ts b/src/torus.ts index 11e54f3..26a69ea 100644 --- a/src/torus.ts +++ b/src/torus.ts @@ -171,10 +171,10 @@ class Torus { async getPublicAddress( endpoints: string[], torusNodePubs: INodePub[], - { verifier, verifierId, extendedVerifierId }: { verifier: string; verifierId: string; extendedVerifierId?: string } + { verifier, verifierId, extendedVerifierId, keyType }: { verifier: string; verifierId: string; extendedVerifierId?: string; keyType: KeyType } ): Promise { log.info(torusNodePubs, { verifier, verifierId, extendedVerifierId }); - return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId }, this.enableOneKey); + return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId, keyType }, this.enableOneKey); } async importPrivateKey(params: ImportKeyParams): Promise { @@ -264,15 +264,17 @@ class Torus { private async getNewPublicAddress( endpoints: string[], - { verifier, verifierId, extendedVerifierId }: { verifier: string; verifierId: string; extendedVerifierId?: string }, + { verifier, verifierId, extendedVerifierId, keyType }: { verifier: string; verifierId: string; extendedVerifierId?: string; keyType?: KeyType }, enableOneKey: boolean ): Promise { + const localKeyType = keyType ?? this.keyType; + const keyAssignResult = await GetPubKeyOrKeyAssign({ endpoints, network: this.network, verifier, verifierId, - keyType: this.keyType, + keyType: localKeyType, extendedVerifierId, }); @@ -330,14 +332,14 @@ class Torus { } const oAuthX = oAuthPubKey.getX().toString(16, 64); const oAuthY = oAuthPubKey.getY().toString(16, 64); - const oAuthAddress = generateAddressFromPubKey(this.keyType, oAuthPubKey.getX(), oAuthPubKey.getY()); + const oAuthAddress = generateAddressFromPubKey(localKeyType, oAuthPubKey.getX(), oAuthPubKey.getY()); if (!finalPubKey) { throw new Error("Unable to derive finalPubKey"); } const finalX = finalPubKey ? finalPubKey.getX().toString(16, 64) : ""; const finalY = finalPubKey ? finalPubKey.getY().toString(16, 64) : ""; - const finalAddress = finalPubKey ? generateAddressFromPubKey(this.keyType, finalPubKey.getX(), finalPubKey.getY()) : ""; + const finalAddress = finalPubKey ? generateAddressFromPubKey(localKeyType, finalPubKey.getX(), finalPubKey.getY()) : ""; return { oAuthKeyData: { walletAddress: oAuthAddress, From 8d8ea357ba9aff081173d2300d0ee6c91fa04f97 Mon Sep 17 00:00:00 2001 From: ieow Date: Tue, 7 Jan 2025 12:47:26 +0800 Subject: [PATCH 2/7] fix: use localEc for getPublicAddress --- src/helpers/keyUtils.ts | 20 ++++++++++++++++++++ src/torus.ts | 36 +++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/helpers/keyUtils.ts b/src/helpers/keyUtils.ts index a618068..7d3e90f 100644 --- a/src/helpers/keyUtils.ts +++ b/src/helpers/keyUtils.ts @@ -13,6 +13,26 @@ import { encParamsBufToHex, generatePrivateKey, getKeyCurve, keccak256 } from ". import { generateRandomPolynomial } from "./langrangeInterpolatePoly"; import { generateNonceMetadataParams, getSecpKeyFromEd25519 } from "./metadataUtils"; +const secp256k1EC = new EC("secp256k1"); +const ed25519EC = new EC("ed25519"); + +/** + * Returns the correct elliptic curve for the given keyType. + * + * @param keyType - The key type to get the curve for. + * @throws \{Error\} If the keyType is not valid. + * @returns \{EC\} The elliptic curve. + * + */ +export const getEcCurve = (keyType: KeyType): EC => { + if (keyType === KEY_TYPE.SECP256K1) { + return secp256k1EC; + } else if (keyType === KEY_TYPE.ED25519) { + return ed25519EC; + } + throw new Error(`Invalid keyType: ${keyType}`); +}; + export function stripHexPrefix(str: string): string { return str.startsWith("0x") ? str.slice(2) : str; } diff --git a/src/torus.ts b/src/torus.ts index 26a69ea..be239ea 100644 --- a/src/torus.ts +++ b/src/torus.ts @@ -16,6 +16,7 @@ import { encodeEd25519Point, generateAddressFromPubKey, generateShares, + getEcCurve, getEd25519ExtendedPublicKey, getMetadata, getOrSetNonce, @@ -268,6 +269,7 @@ class Torus { enableOneKey: boolean ): Promise { const localKeyType = keyType ?? this.keyType; + const localEc = getEcCurve(localKeyType); const keyAssignResult = await GetPubKeyOrKeyAssign({ endpoints, @@ -305,7 +307,7 @@ class Torus { let finalPubKey: curve.base.BasePoint; if (extendedVerifierId) { // for tss key no need to add pub nonce - finalPubKey = this.ec.keyFromPublic({ x: X, y: Y }).getPublic(); + finalPubKey = localEc.keyFromPublic({ x: X, y: Y }).getPublic(); oAuthPubKey = finalPubKey; } else if (LEGACY_NETWORKS_ROUTE_MAP[this.network as TORUS_LEGACY_NETWORK_TYPE]) { return this.formatLegacyPublicKeyData({ @@ -318,11 +320,11 @@ class Torus { }); } else { const v2NonceResult = nonceResult as v2NonceResultType; - oAuthPubKey = this.ec.keyFromPublic({ x: X, y: Y }).getPublic(); - finalPubKey = this.ec + oAuthPubKey = localEc.keyFromPublic({ x: X, y: Y }).getPublic(); + finalPubKey = localEc .keyFromPublic({ x: X, y: Y }) .getPublic() - .add(this.ec.keyFromPublic({ x: v2NonceResult.pubNonce.x, y: v2NonceResult.pubNonce.y }).getPublic()); + .add(localEc.keyFromPublic({ x: v2NonceResult.pubNonce.x, y: v2NonceResult.pubNonce.y }).getPublic()); pubNonce = { X: v2NonceResult.pubNonce.x, Y: v2NonceResult.pubNonce.y }; } @@ -369,8 +371,12 @@ class Torus { enableOneKey: boolean; isNewKey: boolean; serverTimeOffset: number; + keyType?: KeyType; }): Promise { - const { finalKeyResult, enableOneKey, isNewKey, serverTimeOffset } = params; + const { finalKeyResult, enableOneKey, isNewKey, serverTimeOffset, keyType } = params; + const localKeyType = keyType ?? this.keyType; + const localEc = getEcCurve(localKeyType); + const { pub_key_X: X, pub_key_Y: Y } = finalKeyResult.keys[0]; let nonceResult: GetOrSetNonceResult; let nonce: BN; @@ -378,12 +384,12 @@ class Torus { let typeOfUser: GetOrSetNonceResult["typeOfUser"]; let pubNonce: { X: string; Y: string } | undefined; - const oAuthPubKey = this.ec.keyFromPublic({ x: X, y: Y }).getPublic(); + const oAuthPubKey = localEc.keyFromPublic({ x: X, y: Y }).getPublic(); const finalServerTimeOffset = this.serverTimeOffset || serverTimeOffset; if (enableOneKey) { try { - nonceResult = await getOrSetNonce(this.legacyMetadataHost, this.ec, finalServerTimeOffset, X, Y, undefined, !isNewKey); + nonceResult = await getOrSetNonce(this.legacyMetadataHost, localEc, finalServerTimeOffset, X, Y, undefined, !isNewKey); nonce = new BN(nonceResult.nonce || "0", 16); typeOfUser = nonceResult.typeOfUser; } catch { @@ -391,15 +397,15 @@ class Torus { } if (nonceResult.typeOfUser === "v1") { nonce = await getMetadata(this.legacyMetadataHost, { pub_key_X: X, pub_key_Y: Y }); - finalPubKey = this.ec + finalPubKey = localEc .keyFromPublic({ x: X, y: Y }) .getPublic() - .add(this.ec.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic()); + .add(localEc.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic()); } else if (nonceResult.typeOfUser === "v2") { - finalPubKey = this.ec + finalPubKey = localEc .keyFromPublic({ x: X, y: Y }) .getPublic() - .add(this.ec.keyFromPublic({ x: nonceResult.pubNonce.x, y: nonceResult.pubNonce.y }).getPublic()); + .add(localEc.keyFromPublic({ x: nonceResult.pubNonce.x, y: nonceResult.pubNonce.y }).getPublic()); pubNonce = { X: nonceResult.pubNonce.x, Y: nonceResult.pubNonce.y }; } else { throw new Error("getOrSetNonce should always return typeOfUser."); @@ -407,10 +413,10 @@ class Torus { } else { typeOfUser = "v1"; nonce = await getMetadata(this.legacyMetadataHost, { pub_key_X: X, pub_key_Y: Y }); - finalPubKey = this.ec + finalPubKey = localEc .keyFromPublic({ x: X, y: Y }) .getPublic() - .add(this.ec.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic()); + .add(localEc.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic()); } if (!oAuthPubKey) { @@ -418,14 +424,14 @@ class Torus { } const oAuthX = oAuthPubKey.getX().toString(16, 64); const oAuthY = oAuthPubKey.getY().toString(16, 64); - const oAuthAddress = generateAddressFromPubKey(this.keyType, oAuthPubKey.getX(), oAuthPubKey.getY()); + const oAuthAddress = generateAddressFromPubKey(localKeyType, oAuthPubKey.getX(), oAuthPubKey.getY()); if (typeOfUser === "v2" && !finalPubKey) { throw new Error("Unable to derive finalPubKey"); } const finalX = finalPubKey ? finalPubKey.getX().toString(16, 64) : ""; const finalY = finalPubKey ? finalPubKey.getY().toString(16, 64) : ""; - const finalAddress = finalPubKey ? generateAddressFromPubKey(this.keyType, finalPubKey.getX(), finalPubKey.getY()) : ""; + const finalAddress = finalPubKey ? generateAddressFromPubKey(localKeyType, finalPubKey.getX(), finalPubKey.getY()) : ""; return { oAuthKeyData: { walletAddress: oAuthAddress, From 08cd46060755766804addfe4354f0abf2ad35ad9 Mon Sep 17 00:00:00 2001 From: ieow Date: Tue, 7 Jan 2025 13:02:34 +0800 Subject: [PATCH 3/7] fix: optional keyType --- src/torus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/torus.ts b/src/torus.ts index be239ea..a4c9555 100644 --- a/src/torus.ts +++ b/src/torus.ts @@ -172,7 +172,7 @@ class Torus { async getPublicAddress( endpoints: string[], torusNodePubs: INodePub[], - { verifier, verifierId, extendedVerifierId, keyType }: { verifier: string; verifierId: string; extendedVerifierId?: string; keyType: KeyType } + { verifier, verifierId, extendedVerifierId, keyType }: { verifier: string; verifierId: string; extendedVerifierId?: string; keyType?: KeyType } ): Promise { log.info(torusNodePubs, { verifier, verifierId, extendedVerifierId }); return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId, keyType }, this.enableOneKey); From e1431dc3ccb663b6120b4eb211600d4f1f9052f7 Mon Sep 17 00:00:00 2001 From: ieow Date: Tue, 7 Jan 2025 13:30:48 +0800 Subject: [PATCH 4/7] add tests --- test/sapphire_devnet.test.ts | 31 ++++++++++++++++++++++++++++ test/sapphire_devnet_ed25519.test.ts | 31 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/test/sapphire_devnet.test.ts b/test/sapphire_devnet.test.ts index 8cc2e8f..003bab2 100644 --- a/test/sapphire_devnet.test.ts +++ b/test/sapphire_devnet.test.ts @@ -240,6 +240,37 @@ describe("torus utils sapphire devnet", function () { }); }); + it("should should fetch public address with keyType", async function () { + const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: "Willa_Funk11@gmail.com" }; + const nodeDetails = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails); + const torusNodeEndpoints = nodeDetails.torusNodeSSSEndpoints; + const result = await torus.getPublicAddress(torusNodeEndpoints, nodeDetails.torusNodePub, { ...verifierDetails, keyType: "ed25519" }); + expect(result.finalKeyData.walletAddress).eql("HHmiJMCAwhyf9ZWNtj7FEKGXeeC2NjUjPobpDKm43yKs"); + delete result.metadata.serverTimeOffset; + expect(result).eql({ + oAuthKeyData: { + walletAddress: "49yLu8yLqpuCXchzjQSt1tpBz8AP2E9EzzP7a8QtxmTE", + X: "5d39eba90fafbce150b33b9a60b41e1cfdf9e2640b55bf96b787173d74f8e415", + Y: "099639b7da35c1f31a44da7399a29d7db8eaa9639582cf7ed80aa4f7216adf2e", + }, + finalKeyData: { + walletAddress: "HHmiJMCAwhyf9ZWNtj7FEKGXeeC2NjUjPobpDKm43yKs", + X: "575203523b34bcfa2c25c428871c421afd69dbcb7375833b52ef264aaa466a81", + Y: "26f0b1f5740088c2ecf676081b8e2fe5254f1cbb693947ae391af13500d706f2", + }, + metadata: { + pubNonce: { + X: "71bf997547c1ac3f0babee87ebac055e8542863ebb1ba66e8092499eacbffd22", + Y: "71a0a70c5ae06d7eeb45673d4081fdfc9f29c4acfbbb57bf52a33dd7630599b1", + }, + nonce: new BN("0", "hex"), + typeOfUser: "v2", + upgraded: false, + }, + nodesData: result.nodesData, + }); + }); + it("should fetch public address of imported user", async function () { const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_IMPORT_EMAIL }; const nodeDetails = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails); diff --git a/test/sapphire_devnet_ed25519.test.ts b/test/sapphire_devnet_ed25519.test.ts index ad77998..52e8343 100644 --- a/test/sapphire_devnet_ed25519.test.ts +++ b/test/sapphire_devnet_ed25519.test.ts @@ -65,6 +65,37 @@ describe("torus utils ed25519 sapphire devnet", function () { }); }); + it("should should fetch public address with keyType", async function () { + const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: "Willa_Funk11@gmail.com" }; + const nodeDetails = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails); + const torusNodeEndpoints = nodeDetails.torusNodeSSSEndpoints; + const result = await torus.getPublicAddress(torusNodeEndpoints, nodeDetails.torusNodePub, { ...verifierDetails, keyType: "secp256k1" }); + expect(result.finalKeyData.walletAddress).eql("0xc53Df7C3Eb4990CfB8f903e4240dBB3BBa715A96"); + delete result.metadata.serverTimeOffset; + expect(result).eql({ + oAuthKeyData: { + walletAddress: "0x27890B4B87E5a39CA0510B32B2b2621d7D1eF7c0", + X: "d594a7c8368d37b2ca31b55be7db1b6a6bce9a3ddbcc573d5460bc7d630024e3", + Y: "09416f76bdbb88307900f748f0edc1cc345a9ba78c98508c8e29236d98b1d043", + }, + finalKeyData: { + walletAddress: "0xc53Df7C3Eb4990CfB8f903e4240dBB3BBa715A96", + X: "c60e9fbdb820c2ea430769fce86e2fd56ac4a4e5137346d54a914d57c56cab22", + Y: "02df3331a556d429baea94b0da05ec9438ea2ba9912af0fc4b76925531fc4629", + }, + metadata: { + pubNonce: { + X: "d3edb1a89af7db7a078e73cfdb59f9be82512e8121751934122f104b28b92074", + Y: "2a2700c2934c0a0b5cdfaeeca5a4e279fc9d46c6b6837de6f2e2f15ad39c51a3", + }, + nonce: new BN("0", "hex"), + typeOfUser: "v2", + upgraded: false, + }, + nodesData: result.nodesData, + }); + }); + it("should be able to import a key for a new user", async function () { const email = faker.internet.email(); const token = generateIdToken(email, "ES256"); From 270a36c5dea4abf14c3d981008f8f6cce109155c Mon Sep 17 00:00:00 2001 From: ieow Date: Wed, 26 Feb 2025 02:50:02 +0800 Subject: [PATCH 5/7] fix: comment redundance function --- src/helpers/common.ts | 11 +++++++---- src/helpers/keyUtils.ts | 20 -------------------- src/torus.ts | 6 +++--- 3 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/helpers/common.ts b/src/helpers/common.ts index ae2b36e..737e066 100644 --- a/src/helpers/common.ts +++ b/src/helpers/common.ts @@ -16,11 +16,14 @@ export const generatePrivateKey = (ecCurve: EC, buf: typeof Buffer): Buffer => { return ecCurve.genKeyPair().getPrivate().toArrayLike(buf); }; +const secp256k1EC = new EC("secp256k1"); +const ed25519EC = new EC("ed25519"); + export const getKeyCurve = (keyType: KeyType) => { - if (keyType === KEY_TYPE.ED25519) { - return new EC(KEY_TYPE.ED25519); - } else if (keyType === KEY_TYPE.SECP256K1) { - return new EC(KEY_TYPE.SECP256K1); + if (keyType === KEY_TYPE.SECP256K1) { + return secp256k1EC; + } else if (keyType === KEY_TYPE.ED25519) { + return ed25519EC; } throw new Error(`Invalid keyType: ${keyType}`); }; diff --git a/src/helpers/keyUtils.ts b/src/helpers/keyUtils.ts index 7d3e90f..a618068 100644 --- a/src/helpers/keyUtils.ts +++ b/src/helpers/keyUtils.ts @@ -13,26 +13,6 @@ import { encParamsBufToHex, generatePrivateKey, getKeyCurve, keccak256 } from ". import { generateRandomPolynomial } from "./langrangeInterpolatePoly"; import { generateNonceMetadataParams, getSecpKeyFromEd25519 } from "./metadataUtils"; -const secp256k1EC = new EC("secp256k1"); -const ed25519EC = new EC("ed25519"); - -/** - * Returns the correct elliptic curve for the given keyType. - * - * @param keyType - The key type to get the curve for. - * @throws \{Error\} If the keyType is not valid. - * @returns \{EC\} The elliptic curve. - * - */ -export const getEcCurve = (keyType: KeyType): EC => { - if (keyType === KEY_TYPE.SECP256K1) { - return secp256k1EC; - } else if (keyType === KEY_TYPE.ED25519) { - return ed25519EC; - } - throw new Error(`Invalid keyType: ${keyType}`); -}; - export function stripHexPrefix(str: string): string { return str.startsWith("0x") ? str.slice(2) : str; } diff --git a/src/torus.ts b/src/torus.ts index a4c9555..71dbde7 100644 --- a/src/torus.ts +++ b/src/torus.ts @@ -16,8 +16,8 @@ import { encodeEd25519Point, generateAddressFromPubKey, generateShares, - getEcCurve, getEd25519ExtendedPublicKey, + getKeyCurve, getMetadata, getOrSetNonce, GetOrSetNonceError, @@ -269,7 +269,7 @@ class Torus { enableOneKey: boolean ): Promise { const localKeyType = keyType ?? this.keyType; - const localEc = getEcCurve(localKeyType); + const localEc = getKeyCurve(localKeyType); const keyAssignResult = await GetPubKeyOrKeyAssign({ endpoints, @@ -375,7 +375,7 @@ class Torus { }): Promise { const { finalKeyResult, enableOneKey, isNewKey, serverTimeOffset, keyType } = params; const localKeyType = keyType ?? this.keyType; - const localEc = getEcCurve(localKeyType); + const localEc = getKeyCurve(localKeyType); const { pub_key_X: X, pub_key_Y: Y } = finalKeyResult.keys[0]; let nonceResult: GetOrSetNonceResult; From 6d824dc841854dfd3075c552583fbb6edc1c365a Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 27 Feb 2025 15:58:06 +0800 Subject: [PATCH 6/7] fix: address comment --- src/helpers/common.ts | 6 ++++-- src/torus.ts | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/helpers/common.ts b/src/helpers/common.ts index 737e066..5ad34ba 100644 --- a/src/helpers/common.ts +++ b/src/helpers/common.ts @@ -16,13 +16,15 @@ export const generatePrivateKey = (ecCurve: EC, buf: typeof Buffer): Buffer => { return ecCurve.genKeyPair().getPrivate().toArrayLike(buf); }; -const secp256k1EC = new EC("secp256k1"); -const ed25519EC = new EC("ed25519"); +let secp256k1EC: EC; +let ed25519EC: EC; export const getKeyCurve = (keyType: KeyType) => { if (keyType === KEY_TYPE.SECP256K1) { + if (!secp256k1EC) secp256k1EC = new EC("secp256k1"); return secp256k1EC; } else if (keyType === KEY_TYPE.ED25519) { + if (!ed25519EC) ed25519EC = new EC("ed25519"); return ed25519EC; } throw new Error(`Invalid keyType: ${keyType}`); diff --git a/src/torus.ts b/src/torus.ts index 71dbde7..251a19d 100644 --- a/src/torus.ts +++ b/src/torus.ts @@ -175,7 +175,8 @@ class Torus { { verifier, verifierId, extendedVerifierId, keyType }: { verifier: string; verifierId: string; extendedVerifierId?: string; keyType?: KeyType } ): Promise { log.info(torusNodePubs, { verifier, verifierId, extendedVerifierId }); - return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId, keyType }, this.enableOneKey); + const localKeyType = keyType ?? this.keyType; + return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId, keyType: localKeyType }, this.enableOneKey); } async importPrivateKey(params: ImportKeyParams): Promise { From 11e91be39cbb4a584d5cecfb01202bccc52a66bf Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 27 Feb 2025 16:04:20 +0800 Subject: [PATCH 7/7] fix: add check for legacy network with keyType ed25519 --- src/torus.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/torus.ts b/src/torus.ts index 251a19d..62095a5 100644 --- a/src/torus.ts +++ b/src/torus.ts @@ -272,6 +272,10 @@ class Torus { const localKeyType = keyType ?? this.keyType; const localEc = getKeyCurve(localKeyType); + if (localKeyType === KEY_TYPE.ED25519 && LEGACY_NETWORKS_ROUTE_MAP[this.network as TORUS_LEGACY_NETWORK_TYPE]) { + throw new Error(`keyType: ${keyType} is not supported by ${this.network} network`); + } + const keyAssignResult = await GetPubKeyOrKeyAssign({ endpoints, network: this.network,