Skip to content
Merged
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
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 () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you use existing test case and user for testcase to validate nothing changes on passing keyType for existing test user

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Willa_Funk11@gmail.com is existing testcase's email in the sapphire_devnet_ed25519.test.ts

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);
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: "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");
Expand Down