Skip to content

Commit 169265f

Browse files
Merge pull request #170 from torusresearch/feat/getPublicAddress-keytype
Feat/get public address keytype
2 parents bfaa56e + 11e91be commit 169265f

File tree

4 files changed

+105
-25
lines changed

4 files changed

+105
-25
lines changed

src/helpers/common.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ export const generatePrivateKey = (ecCurve: EC, buf: typeof Buffer): Buffer => {
1616
return ecCurve.genKeyPair().getPrivate().toArrayLike(buf);
1717
};
1818

19+
let secp256k1EC: EC;
20+
let ed25519EC: EC;
21+
1922
export const getKeyCurve = (keyType: KeyType) => {
20-
if (keyType === KEY_TYPE.ED25519) {
21-
return new EC(KEY_TYPE.ED25519);
22-
} else if (keyType === KEY_TYPE.SECP256K1) {
23-
return new EC(KEY_TYPE.SECP256K1);
23+
if (keyType === KEY_TYPE.SECP256K1) {
24+
if (!secp256k1EC) secp256k1EC = new EC("secp256k1");
25+
return secp256k1EC;
26+
} else if (keyType === KEY_TYPE.ED25519) {
27+
if (!ed25519EC) ed25519EC = new EC("ed25519");
28+
return ed25519EC;
2429
}
2530
throw new Error(`Invalid keyType: ${keyType}`);
2631
};

src/torus.ts

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
generateAddressFromPubKey,
1818
generateShares,
1919
getEd25519ExtendedPublicKey,
20+
getKeyCurve,
2021
getMetadata,
2122
getOrSetNonce,
2223
GetOrSetNonceError,
@@ -171,10 +172,11 @@ class Torus {
171172
async getPublicAddress(
172173
endpoints: string[],
173174
torusNodePubs: INodePub[],
174-
{ verifier, verifierId, extendedVerifierId }: { verifier: string; verifierId: string; extendedVerifierId?: string }
175+
{ verifier, verifierId, extendedVerifierId, keyType }: { verifier: string; verifierId: string; extendedVerifierId?: string; keyType?: KeyType }
175176
): Promise<TorusPublicKey> {
176177
log.info(torusNodePubs, { verifier, verifierId, extendedVerifierId });
177-
return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId }, this.enableOneKey);
178+
const localKeyType = keyType ?? this.keyType;
179+
return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId, keyType: localKeyType }, this.enableOneKey);
178180
}
179181

180182
async importPrivateKey(params: ImportKeyParams): Promise<TorusKey> {
@@ -264,15 +266,22 @@ class Torus {
264266

265267
private async getNewPublicAddress(
266268
endpoints: string[],
267-
{ verifier, verifierId, extendedVerifierId }: { verifier: string; verifierId: string; extendedVerifierId?: string },
269+
{ verifier, verifierId, extendedVerifierId, keyType }: { verifier: string; verifierId: string; extendedVerifierId?: string; keyType?: KeyType },
268270
enableOneKey: boolean
269271
): Promise<TorusPublicKey> {
272+
const localKeyType = keyType ?? this.keyType;
273+
const localEc = getKeyCurve(localKeyType);
274+
275+
if (localKeyType === KEY_TYPE.ED25519 && LEGACY_NETWORKS_ROUTE_MAP[this.network as TORUS_LEGACY_NETWORK_TYPE]) {
276+
throw new Error(`keyType: ${keyType} is not supported by ${this.network} network`);
277+
}
278+
270279
const keyAssignResult = await GetPubKeyOrKeyAssign({
271280
endpoints,
272281
network: this.network,
273282
verifier,
274283
verifierId,
275-
keyType: this.keyType,
284+
keyType: localKeyType,
276285
extendedVerifierId,
277286
});
278287

@@ -303,7 +312,7 @@ class Torus {
303312
let finalPubKey: curve.base.BasePoint;
304313
if (extendedVerifierId) {
305314
// for tss key no need to add pub nonce
306-
finalPubKey = this.ec.keyFromPublic({ x: X, y: Y }).getPublic();
315+
finalPubKey = localEc.keyFromPublic({ x: X, y: Y }).getPublic();
307316
oAuthPubKey = finalPubKey;
308317
} else if (LEGACY_NETWORKS_ROUTE_MAP[this.network as TORUS_LEGACY_NETWORK_TYPE]) {
309318
return this.formatLegacyPublicKeyData({
@@ -316,11 +325,11 @@ class Torus {
316325
});
317326
} else {
318327
const v2NonceResult = nonceResult as v2NonceResultType;
319-
oAuthPubKey = this.ec.keyFromPublic({ x: X, y: Y }).getPublic();
320-
finalPubKey = this.ec
328+
oAuthPubKey = localEc.keyFromPublic({ x: X, y: Y }).getPublic();
329+
finalPubKey = localEc
321330
.keyFromPublic({ x: X, y: Y })
322331
.getPublic()
323-
.add(this.ec.keyFromPublic({ x: v2NonceResult.pubNonce.x, y: v2NonceResult.pubNonce.y }).getPublic());
332+
.add(localEc.keyFromPublic({ x: v2NonceResult.pubNonce.x, y: v2NonceResult.pubNonce.y }).getPublic());
324333

325334
pubNonce = { X: v2NonceResult.pubNonce.x, Y: v2NonceResult.pubNonce.y };
326335
}
@@ -330,14 +339,14 @@ class Torus {
330339
}
331340
const oAuthX = oAuthPubKey.getX().toString(16, 64);
332341
const oAuthY = oAuthPubKey.getY().toString(16, 64);
333-
const oAuthAddress = generateAddressFromPubKey(this.keyType, oAuthPubKey.getX(), oAuthPubKey.getY());
342+
const oAuthAddress = generateAddressFromPubKey(localKeyType, oAuthPubKey.getX(), oAuthPubKey.getY());
334343

335344
if (!finalPubKey) {
336345
throw new Error("Unable to derive finalPubKey");
337346
}
338347
const finalX = finalPubKey ? finalPubKey.getX().toString(16, 64) : "";
339348
const finalY = finalPubKey ? finalPubKey.getY().toString(16, 64) : "";
340-
const finalAddress = finalPubKey ? generateAddressFromPubKey(this.keyType, finalPubKey.getX(), finalPubKey.getY()) : "";
349+
const finalAddress = finalPubKey ? generateAddressFromPubKey(localKeyType, finalPubKey.getX(), finalPubKey.getY()) : "";
341350
return {
342351
oAuthKeyData: {
343352
walletAddress: oAuthAddress,
@@ -367,63 +376,67 @@ class Torus {
367376
enableOneKey: boolean;
368377
isNewKey: boolean;
369378
serverTimeOffset: number;
379+
keyType?: KeyType;
370380
}): Promise<TorusPublicKey> {
371-
const { finalKeyResult, enableOneKey, isNewKey, serverTimeOffset } = params;
381+
const { finalKeyResult, enableOneKey, isNewKey, serverTimeOffset, keyType } = params;
382+
const localKeyType = keyType ?? this.keyType;
383+
const localEc = getKeyCurve(localKeyType);
384+
372385
const { pub_key_X: X, pub_key_Y: Y } = finalKeyResult.keys[0];
373386
let nonceResult: GetOrSetNonceResult;
374387
let nonce: BN;
375388
let finalPubKey: curve.base.BasePoint;
376389
let typeOfUser: GetOrSetNonceResult["typeOfUser"];
377390
let pubNonce: { X: string; Y: string } | undefined;
378391

379-
const oAuthPubKey = this.ec.keyFromPublic({ x: X, y: Y }).getPublic();
392+
const oAuthPubKey = localEc.keyFromPublic({ x: X, y: Y }).getPublic();
380393

381394
const finalServerTimeOffset = this.serverTimeOffset || serverTimeOffset;
382395
if (enableOneKey) {
383396
try {
384-
nonceResult = await getOrSetNonce(this.legacyMetadataHost, this.ec, finalServerTimeOffset, X, Y, undefined, !isNewKey);
397+
nonceResult = await getOrSetNonce(this.legacyMetadataHost, localEc, finalServerTimeOffset, X, Y, undefined, !isNewKey);
385398
nonce = new BN(nonceResult.nonce || "0", 16);
386399
typeOfUser = nonceResult.typeOfUser;
387400
} catch {
388401
throw new GetOrSetNonceError();
389402
}
390403
if (nonceResult.typeOfUser === "v1") {
391404
nonce = await getMetadata(this.legacyMetadataHost, { pub_key_X: X, pub_key_Y: Y });
392-
finalPubKey = this.ec
405+
finalPubKey = localEc
393406
.keyFromPublic({ x: X, y: Y })
394407
.getPublic()
395-
.add(this.ec.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic());
408+
.add(localEc.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic());
396409
} else if (nonceResult.typeOfUser === "v2") {
397-
finalPubKey = this.ec
410+
finalPubKey = localEc
398411
.keyFromPublic({ x: X, y: Y })
399412
.getPublic()
400-
.add(this.ec.keyFromPublic({ x: nonceResult.pubNonce.x, y: nonceResult.pubNonce.y }).getPublic());
413+
.add(localEc.keyFromPublic({ x: nonceResult.pubNonce.x, y: nonceResult.pubNonce.y }).getPublic());
401414
pubNonce = { X: nonceResult.pubNonce.x, Y: nonceResult.pubNonce.y };
402415
} else {
403416
throw new Error("getOrSetNonce should always return typeOfUser.");
404417
}
405418
} else {
406419
typeOfUser = "v1";
407420
nonce = await getMetadata(this.legacyMetadataHost, { pub_key_X: X, pub_key_Y: Y });
408-
finalPubKey = this.ec
421+
finalPubKey = localEc
409422
.keyFromPublic({ x: X, y: Y })
410423
.getPublic()
411-
.add(this.ec.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic());
424+
.add(localEc.keyFromPrivate(nonce.toString(16, 64), "hex").getPublic());
412425
}
413426

414427
if (!oAuthPubKey) {
415428
throw new Error("Unable to derive oAuthPubKey");
416429
}
417430
const oAuthX = oAuthPubKey.getX().toString(16, 64);
418431
const oAuthY = oAuthPubKey.getY().toString(16, 64);
419-
const oAuthAddress = generateAddressFromPubKey(this.keyType, oAuthPubKey.getX(), oAuthPubKey.getY());
432+
const oAuthAddress = generateAddressFromPubKey(localKeyType, oAuthPubKey.getX(), oAuthPubKey.getY());
420433

421434
if (typeOfUser === "v2" && !finalPubKey) {
422435
throw new Error("Unable to derive finalPubKey");
423436
}
424437
const finalX = finalPubKey ? finalPubKey.getX().toString(16, 64) : "";
425438
const finalY = finalPubKey ? finalPubKey.getY().toString(16, 64) : "";
426-
const finalAddress = finalPubKey ? generateAddressFromPubKey(this.keyType, finalPubKey.getX(), finalPubKey.getY()) : "";
439+
const finalAddress = finalPubKey ? generateAddressFromPubKey(localKeyType, finalPubKey.getX(), finalPubKey.getY()) : "";
427440
return {
428441
oAuthKeyData: {
429442
walletAddress: oAuthAddress,

test/sapphire_devnet.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,37 @@ describe("torus utils sapphire devnet", function () {
240240
});
241241
});
242242

243+
it("should should fetch public address with keyType", async function () {
244+
const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: "[email protected]" };
245+
const nodeDetails = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails);
246+
const torusNodeEndpoints = nodeDetails.torusNodeSSSEndpoints;
247+
const result = await torus.getPublicAddress(torusNodeEndpoints, nodeDetails.torusNodePub, { ...verifierDetails, keyType: "ed25519" });
248+
expect(result.finalKeyData.walletAddress).eql("HHmiJMCAwhyf9ZWNtj7FEKGXeeC2NjUjPobpDKm43yKs");
249+
delete result.metadata.serverTimeOffset;
250+
expect(result).eql({
251+
oAuthKeyData: {
252+
walletAddress: "49yLu8yLqpuCXchzjQSt1tpBz8AP2E9EzzP7a8QtxmTE",
253+
X: "5d39eba90fafbce150b33b9a60b41e1cfdf9e2640b55bf96b787173d74f8e415",
254+
Y: "099639b7da35c1f31a44da7399a29d7db8eaa9639582cf7ed80aa4f7216adf2e",
255+
},
256+
finalKeyData: {
257+
walletAddress: "HHmiJMCAwhyf9ZWNtj7FEKGXeeC2NjUjPobpDKm43yKs",
258+
X: "575203523b34bcfa2c25c428871c421afd69dbcb7375833b52ef264aaa466a81",
259+
Y: "26f0b1f5740088c2ecf676081b8e2fe5254f1cbb693947ae391af13500d706f2",
260+
},
261+
metadata: {
262+
pubNonce: {
263+
X: "71bf997547c1ac3f0babee87ebac055e8542863ebb1ba66e8092499eacbffd22",
264+
Y: "71a0a70c5ae06d7eeb45673d4081fdfc9f29c4acfbbb57bf52a33dd7630599b1",
265+
},
266+
nonce: new BN("0", "hex"),
267+
typeOfUser: "v2",
268+
upgraded: false,
269+
},
270+
nodesData: result.nodesData,
271+
});
272+
});
273+
243274
it("should fetch public address of imported user", async function () {
244275
const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_IMPORT_EMAIL };
245276
const nodeDetails = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails);

test/sapphire_devnet_ed25519.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,37 @@ describe("torus utils ed25519 sapphire devnet", function () {
6565
});
6666
});
6767

68+
it("should should fetch public address with keyType", async function () {
69+
const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: "[email protected]" };
70+
const nodeDetails = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails);
71+
const torusNodeEndpoints = nodeDetails.torusNodeSSSEndpoints;
72+
const result = await torus.getPublicAddress(torusNodeEndpoints, nodeDetails.torusNodePub, { ...verifierDetails, keyType: "secp256k1" });
73+
expect(result.finalKeyData.walletAddress).eql("0xc53Df7C3Eb4990CfB8f903e4240dBB3BBa715A96");
74+
delete result.metadata.serverTimeOffset;
75+
expect(result).eql({
76+
oAuthKeyData: {
77+
walletAddress: "0x27890B4B87E5a39CA0510B32B2b2621d7D1eF7c0",
78+
X: "d594a7c8368d37b2ca31b55be7db1b6a6bce9a3ddbcc573d5460bc7d630024e3",
79+
Y: "09416f76bdbb88307900f748f0edc1cc345a9ba78c98508c8e29236d98b1d043",
80+
},
81+
finalKeyData: {
82+
walletAddress: "0xc53Df7C3Eb4990CfB8f903e4240dBB3BBa715A96",
83+
X: "c60e9fbdb820c2ea430769fce86e2fd56ac4a4e5137346d54a914d57c56cab22",
84+
Y: "02df3331a556d429baea94b0da05ec9438ea2ba9912af0fc4b76925531fc4629",
85+
},
86+
metadata: {
87+
pubNonce: {
88+
X: "d3edb1a89af7db7a078e73cfdb59f9be82512e8121751934122f104b28b92074",
89+
Y: "2a2700c2934c0a0b5cdfaeeca5a4e279fc9d46c6b6837de6f2e2f15ad39c51a3",
90+
},
91+
nonce: new BN("0", "hex"),
92+
typeOfUser: "v2",
93+
upgraded: false,
94+
},
95+
nodesData: result.nodesData,
96+
});
97+
});
98+
6899
it("should be able to import a key for a new user", async function () {
69100
const email = faker.internet.email();
70101
const token = generateIdToken(email, "ES256");

0 commit comments

Comments
 (0)