Skip to content

Commit

Permalink
Merge pull request #170 from torusresearch/feat/getPublicAddress-keytype
Browse files Browse the repository at this point in the history
Feat/get public address keytype
  • Loading branch information
himanshuchawla009 authored Feb 27, 2025
2 parents bfaa56e + 11e91be commit 169265f
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 25 deletions.
13 changes: 9 additions & 4 deletions src/helpers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ export const generatePrivateKey = (ecCurve: EC, buf: typeof Buffer): Buffer => {
return ecCurve.genKeyPair().getPrivate().toArrayLike(buf);
};

let secp256k1EC: EC;
let ed25519EC: EC;

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) {
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}`);
};
Expand Down
55 changes: 34 additions & 21 deletions src/torus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
generateAddressFromPubKey,
generateShares,
getEd25519ExtendedPublicKey,
getKeyCurve,
getMetadata,
getOrSetNonce,
GetOrSetNonceError,
Expand Down Expand Up @@ -171,10 +172,11 @@ 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<TorusPublicKey> {
log.info(torusNodePubs, { verifier, verifierId, extendedVerifierId });
return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId }, this.enableOneKey);
const localKeyType = keyType ?? this.keyType;
return this.getNewPublicAddress(endpoints, { verifier, verifierId, extendedVerifierId, keyType: localKeyType }, this.enableOneKey);
}

async importPrivateKey(params: ImportKeyParams): Promise<TorusKey> {
Expand Down Expand Up @@ -264,15 +266,22 @@ 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<TorusPublicKey> {
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,
verifier,
verifierId,
keyType: this.keyType,
keyType: localKeyType,
extendedVerifierId,
});

Expand Down Expand Up @@ -303,7 +312,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({
Expand All @@ -316,11 +325,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 };
}
Expand All @@ -330,14 +339,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,
Expand Down Expand Up @@ -367,63 +376,67 @@ class Torus {
enableOneKey: boolean;
isNewKey: boolean;
serverTimeOffset: number;
keyType?: KeyType;
}): Promise<TorusPublicKey> {
const { finalKeyResult, enableOneKey, isNewKey, serverTimeOffset } = params;
const { finalKeyResult, enableOneKey, isNewKey, serverTimeOffset, keyType } = params;
const localKeyType = keyType ?? this.keyType;
const localEc = getKeyCurve(localKeyType);

const { pub_key_X: X, pub_key_Y: Y } = finalKeyResult.keys[0];
let nonceResult: GetOrSetNonceResult;
let nonce: BN;
let finalPubKey: curve.base.BasePoint;
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 {
throw new GetOrSetNonceError();
}
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.");
}
} 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) {
throw new Error("Unable to derive oAuthPubKey");
}
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,
Expand Down
31 changes: 31 additions & 0 deletions test/sapphire_devnet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: "[email protected]" };
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);
Expand Down
31 changes: 31 additions & 0 deletions test/sapphire_devnet_ed25519.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: "[email protected]" };
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");
Expand Down

0 comments on commit 169265f

Please sign in to comment.