-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #167 from torusresearch/feat/getOrSetTssPubkey
added get or set tss pubkey
- Loading branch information
Showing
3 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Note: Endpoints should be the sss node endpoints along with path | ||
import { JRPCResponse, KEY_TYPE } from "@toruslabs/constants"; | ||
import { generateJsonRPCObject, post } from "@toruslabs/http-helpers"; | ||
import log from "loglevel"; | ||
|
||
import { JRPC_METHODS } from "../constants"; | ||
import { GetORSetKeyResponse, KeyType } from "../interfaces"; | ||
import { Some } from "../some"; | ||
import { normalizeKeysResult, thresholdSame } from "./common"; | ||
|
||
// for ex: [https://node-1.node.web3auth.io/sss/jrpc, https://node-2.node.web3auth.io/sss/jrpc ....] | ||
export const GetOrSetTssDKGPubKey = async (params: { | ||
endpoints: string[]; | ||
verifier: string; | ||
verifierId: string; | ||
tssVerifierId: string; | ||
keyType?: KeyType; | ||
}): Promise<{ | ||
key: { | ||
pubKeyX: string; | ||
pubKeyY: string; | ||
address: string; | ||
createdAt?: number; | ||
}; | ||
isNewKey: boolean; | ||
nodeIndexes: number[]; | ||
}> => { | ||
const { endpoints, verifier, verifierId, tssVerifierId, keyType = KEY_TYPE.SECP256K1 } = params; | ||
const minThreshold = ~~(endpoints.length / 2) + 1; | ||
const lookupPromises = endpoints.map((x) => | ||
post<JRPCResponse<GetORSetKeyResponse>>( | ||
x, | ||
generateJsonRPCObject(JRPC_METHODS.GET_OR_SET_KEY, { | ||
distributed_metadata: true, | ||
verifier, | ||
verifier_id: verifierId, | ||
extended_verifier_id: tssVerifierId, | ||
one_key_flow: true, | ||
key_type: keyType, | ||
fetch_node_index: true, | ||
client_time: Math.floor(Date.now() / 1000).toString(), | ||
}), | ||
{}, | ||
{ | ||
logTracingHeader: false, | ||
} | ||
).catch((err) => log.error(`${JRPC_METHODS.GET_OR_SET_KEY} request failed`, err)) | ||
); | ||
|
||
const nodeIndexes: number[] = []; | ||
const result = await Some< | ||
void | JRPCResponse<GetORSetKeyResponse>, | ||
{ | ||
keyResult: Pick<GetORSetKeyResponse, "keys" | "is_new_key">; | ||
nodeIndexes: number[]; | ||
errorResult: JRPCResponse<GetORSetKeyResponse>["error"]; | ||
} | ||
>(lookupPromises, async (lookupResults) => { | ||
const lookupPubKeys = lookupResults.filter((x1) => { | ||
if (x1 && !x1.error) { | ||
return x1; | ||
} | ||
return false; | ||
}); | ||
|
||
const errorResult = thresholdSame( | ||
lookupResults.map((x2) => x2 && x2.error), | ||
minThreshold | ||
); | ||
|
||
const keyResult = thresholdSame( | ||
lookupPubKeys.map((x3) => x3 && normalizeKeysResult(x3.result)), | ||
minThreshold | ||
); | ||
|
||
if (keyResult || errorResult) { | ||
if (keyResult) { | ||
lookupResults.forEach((x1) => { | ||
if (x1 && x1.result) { | ||
const currentNodePubKey = x1.result.keys[0].pub_key_X.toLowerCase(); | ||
const thresholdPubKey = keyResult.keys[0].pub_key_X.toLowerCase(); | ||
// push only those indexes for nodes who are returning pub key matching with threshold pub key. | ||
// this check is important when different nodes have different keys assigned to a user. | ||
if (currentNodePubKey === thresholdPubKey) { | ||
const nodeIndex = Number.parseInt(x1.result.node_index); | ||
if (nodeIndex) nodeIndexes.push(nodeIndex); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
return Promise.resolve({ keyResult, nodeIndexes, errorResult }); | ||
} | ||
return Promise.reject(new Error(`invalid public key result: ${JSON.stringify(lookupResults)} for tssVerifierId: ${tssVerifierId} `)); | ||
}); | ||
|
||
if (result.errorResult) { | ||
throw new Error(`invalid public key result,errorResult: ${JSON.stringify(result.errorResult)}`); | ||
} | ||
|
||
const key = result.keyResult.keys[0]; | ||
return { | ||
key: { | ||
pubKeyX: key.pub_key_X, | ||
pubKeyY: key.pub_key_Y, | ||
address: key.address, | ||
createdAt: key.created_at, | ||
}, | ||
nodeIndexes: result.nodeIndexes, | ||
isNewKey: result.keyResult.is_new_key, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { TORUS_SAPPHIRE_NETWORK } from "@toruslabs/constants"; | ||
import { NodeDetailManager } from "@toruslabs/fetch-node-details"; | ||
import { expect } from "chai"; | ||
import faker from "faker"; | ||
|
||
import { GetOrSetTssDKGPubKey } from "../src"; | ||
|
||
describe("setTssKey", function () { | ||
const TORUS_EXTENDED_VERIFIER_EMAIL = "[email protected]"; | ||
const TORUS_TEST_VERIFIER = "torus-test-health"; | ||
|
||
let TORUS_NODE_MANAGER: NodeDetailManager; | ||
|
||
beforeEach("one time execution before all tests", async function () { | ||
TORUS_NODE_MANAGER = new NodeDetailManager({ network: TORUS_SAPPHIRE_NETWORK.SAPPHIRE_DEVNET }); | ||
}); | ||
|
||
it("should assign key to tss verifier id", async function () { | ||
const email = faker.internet.email(); | ||
const nonce = 0; | ||
const tssTag = "default"; | ||
const tssVerifierId = `${email}\u0015${tssTag}\u0016${nonce}`; | ||
const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: email }; | ||
|
||
const { torusNodeSSSEndpoints: torusNodeEndpoints } = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails); | ||
|
||
const result = await GetOrSetTssDKGPubKey({ | ||
endpoints: torusNodeEndpoints, | ||
verifier: TORUS_TEST_VERIFIER, | ||
verifierId: email, | ||
tssVerifierId, | ||
}); | ||
expect(result.key.pubKeyX).to.not.equal(null); | ||
}); | ||
|
||
it("should fetch pub address of tss verifier id", async function () { | ||
const email = TORUS_EXTENDED_VERIFIER_EMAIL; | ||
const nonce = 0; | ||
const tssTag = "default"; | ||
const tssVerifierId = `${email}\u0015${tssTag}\u0016${nonce}`; | ||
const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: email }; | ||
|
||
const { torusNodeSSSEndpoints: torusNodeEndpoints } = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails); | ||
|
||
const result = await GetOrSetTssDKGPubKey({ | ||
endpoints: torusNodeEndpoints, | ||
verifier: TORUS_TEST_VERIFIER, | ||
verifierId: email, | ||
tssVerifierId, | ||
}); | ||
delete result.key.createdAt; | ||
expect(result).eql({ | ||
key: { | ||
pubKeyX: "d45d4ad45ec643f9eccd9090c0a2c753b1c991e361388e769c0dfa90c210348c", | ||
pubKeyY: "fdc151b136aa7df94e97cc7d7007e2b45873c4b0656147ec70aad46e178bce1e", | ||
address: "0xBd6Bc8aDC5f2A0526078Fd2016C4335f64eD3a30", | ||
}, | ||
isNewKey: false, | ||
nodeIndexes: result.nodeIndexes, | ||
}); | ||
}); | ||
|
||
it("should fail if more than one endpoints are invalid", async function () { | ||
const email = TORUS_EXTENDED_VERIFIER_EMAIL; | ||
const nonce = 0; | ||
const tssTag = "default"; | ||
const tssVerifierId = `${email}\u0015${tssTag}\u0016${nonce}`; | ||
const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: email }; | ||
|
||
const { torusNodeSSSEndpoints: torusNodeEndpoints } = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails); | ||
torusNodeEndpoints[2] = "https://invalid.torus.com"; | ||
torusNodeEndpoints[3] = "https://invalid.torus.com"; | ||
torusNodeEndpoints[4] = "https://invalid.torus.com"; | ||
try { | ||
await GetOrSetTssDKGPubKey({ | ||
endpoints: torusNodeEndpoints, | ||
verifier: TORUS_TEST_VERIFIER, | ||
verifierId: email, | ||
tssVerifierId, | ||
}); | ||
// If the function doesn't throw an error, fail the test | ||
expect.fail("Expected an error to be thrown"); | ||
} catch (error) { | ||
// Test passes if an error is thrown | ||
expect(error).to.be.instanceOf(Error); | ||
} | ||
}); | ||
}); |