Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/get public address keytype #170

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
20 changes: 20 additions & 0 deletions src/helpers/keyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
50 changes: 29 additions & 21 deletions src/torus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
encodeEd25519Point,
generateAddressFromPubKey,
generateShares,
getEcCurve,
getEd25519ExtendedPublicKey,
getMetadata,
getOrSetNonce,
Expand Down Expand Up @@ -171,10 +172,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<TorusPublicKey> {
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<TorusKey> {
Expand Down Expand Up @@ -264,15 +265,18 @@ 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 = getEcCurve(localKeyType);

const keyAssignResult = await GetPubKeyOrKeyAssign({
endpoints,
network: this.network,
verifier,
verifierId,
keyType: this.keyType,
keyType: localKeyType,
extendedVerifierId,
});

Expand Down Expand Up @@ -303,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({
Expand All @@ -316,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 };
}
Expand All @@ -330,14 +334,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 +371,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 = getEcCurve(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
Loading