Skip to content

Commit 2b45a12

Browse files
Merge pull request #128 from torusresearch/fix/nonce-race-conditions
fix nonce race conditions and threshold check
2 parents f6f9afc + a994433 commit 2b45a12

File tree

6 files changed

+152
-146
lines changed

6 files changed

+152
-146
lines changed

src/helpers/common.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ export const normalizeKeysResult = (result: VerifierLookupResponse) => {
1313
is_new_key: result.is_new_key,
1414
};
1515
if (result && result.keys && result.keys.length > 0) {
16-
finalResult.keys = result.keys.map((key) => {
17-
return {
18-
pub_key_X: key.pub_key_X,
19-
pub_key_Y: key.pub_key_Y,
20-
address: key.address,
21-
};
22-
});
16+
const finalKey = result.keys[0];
17+
finalResult.keys = [
18+
{
19+
pub_key_X: finalKey.pub_key_X,
20+
pub_key_Y: finalKey.pub_key_Y,
21+
address: finalKey.address,
22+
},
23+
];
2324
}
2425
return finalResult;
2526
};

src/helpers/nodeUtils.ts

+32-15
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const GetPubKeyOrKeyAssign = async (params: {
4444
post<JRPCResponse<VerifierLookupResponse>>(
4545
x,
4646
generateJsonRPCObject(JRPC_METHODS.GET_OR_SET_KEY, {
47+
distributed_metadata: true,
4748
verifier,
4849
verifier_id: verifierId.toString(),
4950
extended_verifier_id: extendedVerifierId,
@@ -60,19 +61,11 @@ export const GetPubKeyOrKeyAssign = async (params: {
6061
const result = await Some<void | JRPCResponse<VerifierLookupResponse>, KeyLookupResult>(lookupPromises, (lookupResults) => {
6162
const lookupPubKeys = lookupResults.filter((x1) => {
6263
if (x1 && !x1.error) {
63-
if (!nonceResult) {
64-
// currently only one node returns metadata nonce
65-
// other nodes returns empty object
66-
// pubNonce must be available to derive the public key
67-
const pubNonceX = (x1.result?.keys[0].nonce_data as v2NonceResultType)?.pubNonce?.x;
68-
if (pubNonceX) {
69-
nonceResult = x1.result.keys[0].nonce_data;
70-
}
71-
}
7264
return x1;
7365
}
7466
return false;
7567
});
68+
7669
const errorResult = thresholdSame(
7770
lookupPubKeys.map((x2) => x2 && x2.error),
7871
~~(endpoints.length / 2) + 1
@@ -83,6 +76,22 @@ export const GetPubKeyOrKeyAssign = async (params: {
8376
~~(endpoints.length / 2) + 1
8477
);
8578

79+
// check for nonce result in response if not a extendedVerifierId and not a legacy network
80+
if (keyResult && !nonceResult && !extendedVerifierId && !LEGACY_NETWORKS_ROUTE_MAP[network as TORUS_LEGACY_NETWORK_TYPE]) {
81+
for (let i = 0; i < lookupResults.length; i++) {
82+
const x1 = lookupResults[i];
83+
if (x1 && !x1.error) {
84+
const currentNodePubKey = x1.result.keys[0].pub_key_X.toLowerCase();
85+
const thresholdPubKey = keyResult.keys[0].pub_key_X.toLowerCase();
86+
const pubNonceX = (x1.result?.keys[0].nonce_data as v2NonceResultType)?.pubNonce?.x;
87+
if (pubNonceX && currentNodePubKey === thresholdPubKey) {
88+
nonceResult = x1.result.keys[0].nonce_data;
89+
break;
90+
}
91+
}
92+
}
93+
}
94+
8695
// nonceResult must exist except for extendedVerifierId and legacy networks along with keyResult
8796
if ((keyResult && (nonceResult || extendedVerifierId || LEGACY_NETWORKS_ROUTE_MAP[network as TORUS_LEGACY_NETWORK_TYPE])) || errorResult) {
8897
if (keyResult) {
@@ -257,6 +266,7 @@ export async function retrieveOrImportShare(params: {
257266
generateJsonRPCObject(JRPC_METHODS.IMPORT_SHARE, {
258267
encrypted: "yes",
259268
use_temp: true,
269+
distributed_metadata: true,
260270
item: [
261271
{
262272
...verifierParams,
@@ -286,6 +296,7 @@ export async function retrieveOrImportShare(params: {
286296
generateJsonRPCObject(JRPC_METHODS.GET_SHARE_OR_KEY_ASSIGN, {
287297
encrypted: "yes",
288298
use_temp: true,
299+
distributed_metadata: true,
289300
item: [
290301
{
291302
...verifierParams,
@@ -321,12 +332,6 @@ export async function retrieveOrImportShare(params: {
321332
});
322333
const pubkeys = shareResponses.map((x) => {
323334
if (x && x.result && x.result.keys[0].public_key) {
324-
if (!thresholdNonceData && !verifierParams.extended_verifier_id) {
325-
const pubNonce = (x.result.keys[0].nonce_data as v2NonceResultType)?.pubNonce?.x;
326-
if (pubNonce) {
327-
thresholdNonceData = x.result.keys[0].nonce_data;
328-
}
329-
}
330335
return x.result.keys[0].public_key;
331336
}
332337
return undefined;
@@ -338,6 +343,17 @@ export async function retrieveOrImportShare(params: {
338343
throw new Error("invalid result from nodes, threshold number of public key results are not matching");
339344
}
340345

346+
shareResponses.forEach((x) => {
347+
const requiredShareResponse = x && x.result && x.result.keys[0].public_key && x.result.keys[0];
348+
if (requiredShareResponse && !thresholdNonceData && !verifierParams.extended_verifier_id) {
349+
const currentPubKey = requiredShareResponse.public_key;
350+
const pubNonce = (requiredShareResponse.nonce_data as v2NonceResultType)?.pubNonce?.x;
351+
if (pubNonce && currentPubKey.X === thresholdPublicKey.X) {
352+
thresholdNonceData = requiredShareResponse.nonce_data;
353+
}
354+
}
355+
});
356+
341357
// if both thresholdNonceData and extended_verifier_id are not available
342358
// then we need to throw other wise address would be incorrect.
343359
if (!thresholdNonceData && !verifierParams.extended_verifier_id && !LEGACY_NETWORKS_ROUTE_MAP[network as TORUS_LEGACY_NETWORK_TYPE]) {
@@ -665,6 +681,7 @@ export const legacyKeyAssign = async ({
665681
if (firstPoint !== undefined) initialPoint = firstPoint;
666682

667683
const data = generateJsonRPCObject("KeyAssign", {
684+
distributed_metadata: true,
668685
verifier,
669686
verifier_id: verifierId.toString(),
670687
});

test/aqua.test.ts

+30-24
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,26 @@ describe("torus utils aqua", function () {
5555
const verifierDetails = { verifier, verifierId: TORUS_TEST_EMAIL };
5656
const { torusNodeEndpoints, torusNodePub } = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails);
5757
const result1 = (await torus.getUserTypeAndAddress(torusNodeEndpoints, torusNodePub, verifierDetails)) as TorusPublicKey;
58-
expect(result1.finalKeyData.evmAddress).to.equal("0x79F06350eF34Aeed4BE68e26954D405D573f1438");
59-
expect(result1.metadata.typeOfUser).to.equal("v1");
58+
expect(result1.metadata.typeOfUser).to.equal("v2");
6059
expect(result1).eql({
6160
oAuthKeyData: {
6261
evmAddress: "0xDfA967285AC699A70DA340F60d00DB19A272639d",
6362
X: "4fc8db5d3fe164a3ab70fd6348721f2be848df2cc02fd2db316a154855a7aa7d",
6463
Y: "f76933cbf5fe2916681075bb6cb4cde7d5f6b6ce290071b1b7106747d906457c",
6564
},
6665
finalKeyData: {
67-
evmAddress: "0xDfA967285AC699A70DA340F60d00DB19A272639d",
68-
X: "4fc8db5d3fe164a3ab70fd6348721f2be848df2cc02fd2db316a154855a7aa7d",
69-
Y: "f76933cbf5fe2916681075bb6cb4cde7d5f6b6ce290071b1b7106747d906457c",
66+
evmAddress: "0x79F06350eF34Aeed4BE68e26954D405D573f1438",
67+
X: "99df45abc8e6ee03d2f94df33be79e939eadfbed20c6b88492782fdc3ef1dfd3",
68+
Y: "12bf3e54599a177fdb88f8b22419df7ddf1622e1d2344301edbe090890a72b16",
7069
},
7170
metadata: {
72-
pubNonce: undefined,
71+
pubNonce: {
72+
X: "dc5a031fd2e0b55dbaece314ea125bac9da5f0a916bf156ff36b5ad71380ea32",
73+
Y: "affd749b98c209d2f9cf4dacb145d7897f82f1e2924a47b07874302ecc0b8ef1",
74+
},
7375
nonce: new BN(0),
7476
upgraded: false,
75-
typeOfUser: "v1",
77+
typeOfUser: "v2",
7678
},
7779
nodesData: result1.nodesData,
7880
});
@@ -84,24 +86,26 @@ describe("torus utils aqua", function () {
8486
verifier: v2Verifier,
8587
verifierId: v2TestEmail,
8688
})) as TorusPublicKey;
87-
expect(result2.finalKeyData.evmAddress).to.equal("0x5735dDC8d5125B23d77C3531aab3895A533584a3");
88-
expect(result2.metadata.typeOfUser).to.equal("v1");
89+
expect(result2.metadata.typeOfUser).to.equal("v2");
8990
expect(result2).eql({
9091
oAuthKeyData: {
91-
evmAddress: "0x5735dDC8d5125B23d77C3531aab3895A533584a3",
92-
X: "e1b419bc52b82e14b148c307f10479cfa464d20c947555fb4758c586eab12873",
93-
Y: "75f47d7d5a271c0fcf51a790c1683a1cb3394b1d37d20e29c346ac249e3bfca2",
92+
evmAddress: "0x4ea5260fF85678A2a326D08DF9C44d1f559a5828",
93+
X: "0e6febe33a9d4eeb680cc6b63ff6237ad1971f27adcd7f104a3b1de18eda9337",
94+
Y: "a5a915561f3543688e71281a850b9ee10b9690f305d9e79028dfc8359192b82d",
9495
},
9596
finalKeyData: {
96-
evmAddress: "0x5735dDC8d5125B23d77C3531aab3895A533584a3",
97-
X: "e1b419bc52b82e14b148c307f10479cfa464d20c947555fb4758c586eab12873",
98-
Y: "75f47d7d5a271c0fcf51a790c1683a1cb3394b1d37d20e29c346ac249e3bfca2",
97+
evmAddress: "0xBc32f315515AdE7010cabC5Fd68c966657A570BD",
98+
X: "4897f120584ee18a72b9a6bb92c3ef6e45fc5fdff70beae7dc9325bd01332022",
99+
Y: "2066dbef2fcdded4573e3c04d1c04edd5d44662168e636ed9d0b0cbe2e67c968",
99100
},
100101
metadata: {
101-
pubNonce: undefined,
102+
pubNonce: {
103+
X: "1601cf4dc4362b219260663d5ec5119699fbca185d08b7acb2e36cad914340d5",
104+
Y: "c2f7871f61ee71b4486ac9fb40ec759099800e737139dc5dfaaaed8c9d77c3c1",
105+
},
102106
nonce: new BN(0),
103107
upgraded: false,
104-
typeOfUser: "v1",
108+
typeOfUser: "v2",
105109
},
106110
nodesData: result2.nodesData,
107111
});
@@ -112,24 +116,26 @@ describe("torus utils aqua", function () {
112116
verifier: v2Verifier,
113117
verifierId: v2nTestEmail,
114118
})) as TorusPublicKey;
115-
expect(result3.finalKeyData.evmAddress).to.equal("0x4ce0D09C3989eb3cC9372cC27fa022D721D737dD");
116-
expect(result3.metadata.typeOfUser).to.equal("v1");
119+
expect(result3.metadata.typeOfUser).to.equal("v2");
117120
expect(result3).eql({
118121
oAuthKeyData: {
119122
evmAddress: "0x4ce0D09C3989eb3cC9372cC27fa022D721D737dD",
120123
X: "e76d2f7fa2c0df324b4ab74629c3af47aa4609c35f1d2b6b90b77a47ab9a1281",
121124
Y: "b33b35148d72d357070f66372e07fec436001bdb15c098276b120b9ed64c1e5f",
122125
},
123126
finalKeyData: {
124-
evmAddress: "0x4ce0D09C3989eb3cC9372cC27fa022D721D737dD",
125-
X: "e76d2f7fa2c0df324b4ab74629c3af47aa4609c35f1d2b6b90b77a47ab9a1281",
126-
Y: "b33b35148d72d357070f66372e07fec436001bdb15c098276b120b9ed64c1e5f",
127+
evmAddress: "0x5469C5aCB0F30929226AfF4622918DA8E1424a8D",
128+
X: "c20fac685bb67169e92f1d5d8894d4eea18753c0ef3b7b1b2224233b2dfa3539",
129+
Y: "c4f080b5c8d5c55c8eaba4bec70f668f36db4126f358b491d631fefea7c19d21",
127130
},
128131
metadata: {
129-
pubNonce: undefined,
132+
pubNonce: {
133+
X: "17b1ebce1fa874452a96d0c6d74c1445b78f16957c7decc5d2a202b0ce4662f5",
134+
Y: "b5432cb593753e1b3ecf98b05dc03e57bc02c415e1b80a1ffc5a401ec1f0abd6",
135+
},
130136
nonce: new BN(0),
131137
upgraded: false,
132-
typeOfUser: "v1",
138+
typeOfUser: "v2",
133139
},
134140
nodesData: result3.nodesData,
135141
});

test/cyan.test.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,27 @@ describe("torus utils cyan", function () {
5555
const verifierDetails = { verifier, verifierId: TORUS_TEST_EMAIL };
5656
const { torusNodeEndpoints, torusNodePub } = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails);
5757
const result1 = await torus.getUserTypeAndAddress(torusNodeEndpoints, torusNodePub, verifierDetails);
58-
expect(result1.finalKeyData.evmAddress).to.equal("0xA3767911A84bE6907f26C572bc89426dDdDB2825");
59-
expect(result1.metadata.typeOfUser).to.equal("v1");
58+
expect(result1.finalKeyData.evmAddress).to.equal("0x3507F0d192a44E436B8a6C32a37d57D022861b1a");
59+
expect(result1.metadata.typeOfUser).to.equal("v2");
6060
expect(result1).eql({
6161
oAuthKeyData: {
6262
evmAddress: "0xA3767911A84bE6907f26C572bc89426dDdDB2825",
6363
X: "2853f323437da98ce021d06854f4b292db433c0ad03b204ef223ac2583609a6a",
6464
Y: "f026b4788e23523e0c8fcbf0bdcf1c1a62c9cde8f56170309607a7a52a19f7c1",
6565
},
6666
finalKeyData: {
67-
evmAddress: "0xA3767911A84bE6907f26C572bc89426dDdDB2825",
68-
X: "2853f323437da98ce021d06854f4b292db433c0ad03b204ef223ac2583609a6a",
69-
Y: "f026b4788e23523e0c8fcbf0bdcf1c1a62c9cde8f56170309607a7a52a19f7c1",
67+
evmAddress: "0x3507F0d192a44E436B8a6C32a37d57D022861b1a",
68+
X: "8aaadab9530cb157d0b0dfb7b27d1a3aaca45274563c22c92c77ee2191779051",
69+
Y: "d57b89d9f62bb6609d8542c3057943805c8c72f6f27d39781b820f27d7210f12",
7070
},
7171
metadata: {
72-
pubNonce: undefined,
72+
pubNonce: {
73+
X: "5f2505155e2c1119ee8a76d0f3b22fccee45871d4aab3cb6209bdbc302b5abc2",
74+
Y: "a20f30868759a6095697d5631483faa650f489b33c0e2958ad8dc29e707c0a99",
75+
},
7376
nonce: new BN(0),
7477
upgraded: false,
75-
typeOfUser: "v1",
78+
typeOfUser: "v2",
7679
},
7780
nodesData: result1.nodesData,
7881
});

test/mainnet.test.ts

+18-17
Original file line numberDiff line numberDiff line change
@@ -55,24 +55,26 @@ describe("torus utils mainnet", function () {
5555
const verifierDetails = { verifier, verifierId: TORUS_TEST_EMAIL };
5656
const { torusNodeEndpoints, torusNodePub } = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails);
5757
const result1 = await torus.getUserTypeAndAddress(torusNodeEndpoints, torusNodePub, verifierDetails);
58-
expect(result1.finalKeyData.evmAddress).to.equal("0x0C44AFBb5395a9e8d28DF18e1326aa0F16b9572A");
59-
expect(result1.metadata.typeOfUser).to.equal("v1");
58+
expect(result1.metadata.typeOfUser).to.equal("v2");
6059
expect(result1).eql({
6160
oAuthKeyData: {
6261
evmAddress: "0x0C44AFBb5395a9e8d28DF18e1326aa0F16b9572A",
6362
X: "3b5655d78978b6fd132562b5cb66b11bcd868bd2a9e16babe4a1ca50178e57d4",
6463
Y: "15338510798d6b55db28c121d86babcce19eb9f1882f05fae8ee9b52ed09e8f1",
6564
},
6665
finalKeyData: {
67-
evmAddress: "0x0C44AFBb5395a9e8d28DF18e1326aa0F16b9572A",
68-
X: "3b5655d78978b6fd132562b5cb66b11bcd868bd2a9e16babe4a1ca50178e57d4",
69-
Y: "15338510798d6b55db28c121d86babcce19eb9f1882f05fae8ee9b52ed09e8f1",
66+
evmAddress: "0xb2e1c3119f8D8E73de7eaF7A535FB39A3Ae98C5E",
67+
X: "072beda348a832aed06044a258cb6a8d428ec7c245c5da92db5da4f3ab433e55",
68+
Y: "54ace0d3df2504fa29f17d424a36a0f92703899fad0afee93d010f6d84b310e5",
7069
},
7170
metadata: {
72-
pubNonce: undefined,
71+
pubNonce: {
72+
X: "eb22d93244acf7fcbeb6566da722bc9c8e5433cd28da25ca0650d9cb32806c39",
73+
Y: "765541e214f067cfc44dcf41e582ae09b71c2e607a301cc8a45e1f316a6ba91c",
74+
},
7375
nonce: new BN(0),
7476
upgraded: false,
75-
typeOfUser: "v1",
77+
typeOfUser: "v2",
7678
},
7779
nodesData: result1.nodesData,
7880
});
@@ -115,24 +117,26 @@ describe("torus utils mainnet", function () {
115117
verifier: v2Verifier,
116118
verifierId: v2nTestEmail,
117119
});
118-
expect(result3.finalKeyData.evmAddress).to.equal("0x61E52B6e488EC3dD6FDc0F5ed04a62Bb9c6BeF53");
119-
expect(result3.metadata.typeOfUser).to.equal("v1");
120+
expect(result3.metadata.typeOfUser).to.equal("v2");
120121
expect(result3).eql({
121122
oAuthKeyData: {
122123
evmAddress: "0x61E52B6e488EC3dD6FDc0F5ed04a62Bb9c6BeF53",
123124
X: "c01282dd68d2341031a1cff06f70d821cad45140f425f1c25055a8aa64959df8",
124125
Y: "cb3937773bb819d60b780b6d4c2edcf27c0f7090ba1fc2ff42504a8138a8e2d7",
125126
},
126127
finalKeyData: {
127-
evmAddress: "0x61E52B6e488EC3dD6FDc0F5ed04a62Bb9c6BeF53",
128-
X: "c01282dd68d2341031a1cff06f70d821cad45140f425f1c25055a8aa64959df8",
129-
Y: "cb3937773bb819d60b780b6d4c2edcf27c0f7090ba1fc2ff42504a8138a8e2d7",
128+
evmAddress: "0x40A4A04fDa1f29a3667152C8830112FBd6A77BDD",
129+
X: "6779af3031d9e9eec6b4133b0ae13e367c83a614f92d2008e10c7f3b8e6723bc",
130+
Y: "80edc4502abdfb220dd6e2fcfa2dbb058125dc95873e4bfa6877f9c26da7fdff",
130131
},
131132
metadata: {
132-
pubNonce: undefined,
133+
pubNonce: {
134+
X: "16214bf232167258fb5f98fa9d84968ffec3236aaf0994fc366940c4bc07a5b1",
135+
Y: "475e8c09d2cc8f6c12a767f51c052b1bf8e8d3a2a2b6818d4b199dc283e80ac4",
136+
},
133137
nonce: new BN(0),
134138
upgraded: false,
135-
typeOfUser: "v1",
139+
typeOfUser: "v2",
136140
},
137141
nodesData: result3.nodesData,
138142
});
@@ -159,9 +163,6 @@ describe("torus utils mainnet", function () {
159163
const verifierDetails = { verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL };
160164
const { torusNodeEndpoints, torusIndexes } = await TORUS_NODE_MANAGER.getNodeDetails(verifierDetails);
161165
const result = await torus.retrieveShares(torusNodeEndpoints, torusIndexes, TORUS_TEST_VERIFIER, { verifier_id: TORUS_TEST_EMAIL }, token);
162-
expect(result.oAuthKeyData.evmAddress).to.be.equal("0x90A926b698047b4A87265ba1E9D8b512E8489067");
163-
expect(result.finalKeyData.privKey).to.be.equal("0129494416ab5d5f674692b39fa49680e07d3aac01b9683ee7650e40805d4c44");
164-
expect(result.finalKeyData.evmAddress).to.be.equal("0x90A926b698047b4A87265ba1E9D8b512E8489067");
165166
delete result.sessionData;
166167

167168
expect(result).eql({

0 commit comments

Comments
 (0)