From cea9d89c0e1a5f5a3d9705bada5d27bfd3d93bb5 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Mon, 5 Feb 2024 09:12:09 +0530 Subject: [PATCH 01/23] feat: soft nonce implementation --- package-lock.json | 7 + .../src/baseTypes/aggregateTypes.ts | 3 + packages/core/package.json | 1 + packages/core/src/core.ts | 49 ++++++- packages/core/src/metadata.ts | 14 +- packages/default/test/shared.js | 134 ++++++++++++++---- 6 files changed, 171 insertions(+), 37 deletions(-) diff --git a/package-lock.json b/package-lock.json index 15360ce90..bd013d9a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8092,6 +8092,12 @@ "node": ">= 8" } }, + "node_modules/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in." + }, "node_modules/crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -24286,6 +24292,7 @@ "@toruslabs/rss-client": "^1.5.0", "@toruslabs/torus.js": "^11.0.6", "bn.js": "^5.2.1", + "crypto": "^1.0.1", "elliptic": "^6.5.4", "json-stable-stringify": "^1.0.2" }, diff --git a/packages/common-types/src/baseTypes/aggregateTypes.ts b/packages/common-types/src/baseTypes/aggregateTypes.ts index 71293e4db..5b5937e04 100644 --- a/packages/common-types/src/baseTypes/aggregateTypes.ts +++ b/packages/common-types/src/baseTypes/aggregateTypes.ts @@ -79,6 +79,8 @@ export interface IMetadata extends ISerializable { nonce: number; + chainCode?: string; + getShareIndexesForPolynomial(polyID: PolynomialID): string[]; getLatestPublicPolynomial(): PublicPolynomial; addTSSData(tssData: { @@ -89,6 +91,7 @@ export interface IMetadata extends ISerializable { factorEncs?: { [factorPubID: string]: FactorEnc; }; + chainCode?: string; }): void; addPublicShare(polynomialID: PolynomialID, publicShare: PublicShare): void; setGeneralStoreDomain(key: string, obj: unknown): void; diff --git a/packages/core/package.json b/packages/core/package.json index 05f692cd4..e9d79bf15 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -40,6 +40,7 @@ "@toruslabs/rss-client": "^1.5.0", "@toruslabs/torus.js": "^11.0.6", "bn.js": "^5.2.1", + "crypto": "^1.0.1", "elliptic": "^6.5.4", "json-stable-stringify": "^1.0.2" }, diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index de0769278..ca125b81e 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -52,7 +52,9 @@ import { toPrivKeyECC, } from "@tkey-mpc/common-types"; import { generatePrivate } from "@toruslabs/eccrypto"; +import { keccak256 } from "@toruslabs/torus.js"; import BN from "bn.js"; +import crypto from "crypto"; import stringify from "json-stable-stringify"; import AuthMetadata from "./authMetadata"; @@ -66,7 +68,6 @@ import { lagrangeInterpolation, } from "./lagrangeInterpolatePolynomial"; import Metadata from "./metadata"; - // TODO: handle errors for get and set with retries class ThresholdKey implements ITKey { @@ -226,6 +227,19 @@ class ThresholdKey implements ITKey { throw CoreError.metadataUndefined(); } + computeNonce(index: number) { + // generation should occur during tkey.init, fails if chaincode is absent + const { chainCode } = this.metadata; + if (!chainCode) { + throw CoreError.default("chainCode is absent, required for nonce generation"); + } + return new BN(keccak256(Buffer.from(`${index}${chainCode}`)).slice(2), "hex").umod(ecCurve.curve.n); + } + + generateSalt(length = 32) { + return crypto.randomBytes(length).toString("hex"); + } + async initialize(params?: { withShare?: ShareStore; importKey?: BN; @@ -300,7 +314,8 @@ class ThresholdKey implements ITKey { }); if (useTSS) { const { factorEncs, factorPubs, tssPolyCommits } = await this._initializeNewTSSKey(this.tssTag, deviceTSSShare, factorPub, deviceTSSIndex); - this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: 0, tssPolyCommits, factorPubs, factorEncs }); + const chainCode = this.generateSalt(); + this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: 0, tssPolyCommits, factorPubs, factorEncs, chainCode }); } return this.getKeyDetails(); } @@ -385,7 +400,7 @@ class ThresholdKey implements ITKey { * getTSSShare accepts a factorKey and returns the TSS share based on the factor encrypted TSS shares in the metadata * @param factorKey - factor key */ - async getTSSShare(factorKey: BN, opts?: { threshold: number }): Promise<{ tssIndex: number; tssShare: BN }> { + async getTSSShare(factorKey: BN, opts?: { threshold: number; accountIndex?: number }): Promise<{ tssIndex: number; tssShare: BN }> { if (!this.privKey) throw CoreError.default("tss share cannot be returned until you've reconstructed tkey"); const factorPub = getPubKeyPoint(factorKey); const factorEncs = this.getFactorEncs(factorPub); @@ -407,6 +422,7 @@ class ThresholdKey implements ITKey { const userDec = tssShareBNs[0]; + const { threshold, accountIndex } = opts || {}; if (type === "direct") { const tssSharePub = ecCurve.g.mul(userDec); const tssCommitA0 = ecCurve.keyFromPublic({ x: tssCommits[0].x.toString(16, 64), y: tssCommits[0].y.toString(16, 64) }).getPublic(); @@ -416,6 +432,11 @@ class ThresholdKey implements ITKey { _tssSharePub = _tssSharePub.add(tssCommitA1); } if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { + if (accountIndex && accountIndex > 0) { + const nonce = this.computeNonce(accountIndex); + const derivedShare = userDec.add(nonce).umod(ecCurve.n); + return { tssIndex, tssShare: derivedShare }; + } return { tssIndex, tssShare: userDec }; } throw new Error("user decryption does not match tss commitments..."); @@ -425,8 +446,6 @@ class ThresholdKey implements ITKey { const serverDecs = tssShareBNs.slice(1); // 5 elems const serverIndexes = new Array(serverDecs.length).fill(null).map((_, i) => i + 1); - const { threshold } = opts || {}; - const combis = kCombinations(serverDecs.length, threshold || Math.ceil(serverDecs.length / 2)); for (let i = 0; i < combis.length; i++) { const combi = combis[i]; @@ -445,6 +464,14 @@ class ThresholdKey implements ITKey { for (let j = 0; j < tssIndex; j++) { _tssSharePub = _tssSharePub.add(tssCommitA1); } + if (accountIndex && accountIndex > 0) { + const nonce = this.computeNonce(accountIndex); + const derivedShare = tssShare.add(nonce).umod(ecCurve.n); + if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { + return { tssIndex, tssShare: derivedShare }; + } + } + if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { return { tssIndex, tssShare }; } @@ -461,7 +488,17 @@ class ThresholdKey implements ITKey { return tssPolyCommits; } - getTSSPub(): Point { + getTSSPub(accountIndex?: number): Point { + if (accountIndex && accountIndex > 0) { + const nonce = this.computeNonce(accountIndex); + // we need to add the pub key nonce to the tssPub + const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); + const pubKeyPoint = ecCurve + .keyFromPublic({ x: this.getTSSCommits()[0].x.toString("hex"), y: this.getTSSCommits()[0].y.toString("hex") }) + .getPublic(); + const dervicepubKeyPoint = pubKeyPoint.add(noncePub); + return new Point(dervicepubKeyPoint.getX().toString("hex"), dervicepubKeyPoint.getY().toString("hex")); + } return this.getTSSCommits()[0]; } diff --git a/packages/core/src/metadata.ts b/packages/core/src/metadata.ts index 2c1cde092..5adc27961 100644 --- a/packages/core/src/metadata.ts +++ b/packages/core/src/metadata.ts @@ -68,6 +68,9 @@ class Metadata implements IMetadata { }; }; + // salt + chainCode?: string; + constructor(input: Point) { this.tssPolyCommits = {}; this.tssNonces = {}; @@ -84,7 +87,7 @@ class Metadata implements IMetadata { } static fromJSON(value: StringifiedType): Metadata { - const { pubKey, polyIDList, generalStore, tkeyStore, scopedStore, nonce, tssNonces, tssPolyCommits, factorPubs, factorEncs } = value; + const { pubKey, polyIDList, generalStore, tkeyStore, scopedStore, nonce, tssNonces, tssPolyCommits, factorPubs, factorEncs, chainCode } = value; const point = Point.fromCompressedPub(pubKey); const metadata = new Metadata(point); const unserializedPolyIDList: PolyIDAndShares[] = []; @@ -93,6 +96,7 @@ class Metadata implements IMetadata { if (tkeyStore) metadata.tkeyStore = tkeyStore; if (scopedStore) metadata.scopedStore = scopedStore; if (nonce) metadata.nonce = nonce; + if (chainCode) metadata.chainCode = chainCode; if (tssPolyCommits) { metadata.tssPolyCommits = {}; for (const key in tssPolyCommits) { @@ -186,15 +190,20 @@ class Metadata implements IMetadata { tssNonce?: number; tssPolyCommits?: Point[]; factorPubs?: Point[]; + accountIndex?: number; factorEncs?: { [factorPubID: string]: FactorEnc; }; + chainCode?: string; }): void { - const { tssTag, tssNonce, tssPolyCommits, factorPubs, factorEncs } = tssData; + const { tssTag, tssNonce, tssPolyCommits, factorPubs, factorEncs, chainCode } = tssData; if (tssNonce !== undefined) this.tssNonces[tssTag] = tssNonce; if (tssPolyCommits) this.tssPolyCommits[tssTag] = tssPolyCommits; if (factorPubs) this.factorPubs[tssTag] = factorPubs; if (factorEncs) this.factorEncs[tssTag] = factorEncs; + if (chainCode && !this.chainCode) { + this.chainCode = chainCode; + } } // appends shares and public polynomial to metadata. @@ -338,6 +347,7 @@ class Metadata implements IMetadata { ...(this.tssPolyCommits && { tssPolyCommits: this.tssPolyCommits }), ...(this.factorPubs && { factorPubs: this.factorPubs }), ...(this.factorEncs && { factorEncs: this.factorEncs }), + ...(this.chainCode && { chainCode: this.chainCode }), }; } } diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index 2f74f32c6..156d40e05 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -3,7 +3,7 @@ /* eslint-disable mocha/no-exports */ /* eslint-disable import/no-extraneous-dependencies */ -import { ecCurve, getPubKeyPoint, KEY_NOT_FOUND, SHARE_DELETED, ShareStore } from "@tkey-mpc/common-types"; +import { ecCurve, getPubKeyPoint, KEY_NOT_FOUND, SHARE_DELETED, ShareStore, toPrivKeyEC } from "@tkey-mpc/common-types"; import { Metadata } from "@tkey-mpc/core"; import PrivateKeyModule, { ED25519Format, SECP256K1Format } from "@tkey-mpc/private-keys"; import SecurityQuestionsModule from "@tkey-mpc/security-questions"; @@ -93,6 +93,11 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const storageLayer = initStorageLayer({ hostUrl: metadataURL }); const tb1 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); + // chainCode is absent, required for nonce generation + // can be only initialize with tkey.initialize(); + rejects(async () => { + await tb1.computeNonce(1); + }); // factor key needs to passed from outside of tKey const factorKey = new BN(generatePrivate()); const factorPub = getPubKeyPoint(factorKey); @@ -104,30 +109,55 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { if (tb1.privKey.cmp(reconstructedKey.privKey) !== 0) { fail("key should be able to be reconstructed"); } + const { tssShare: retrievedTSS1, tssIndex: retrievedTSSIndex1 } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); + const tssPrivKey1 = getLagrangeCoeffs([1, retrievedTSSIndex1], 1) + .mul(serverDKGPrivKeys[0].add(tb1.computeNonce(1))) + .add(getLagrangeCoeffs([1, retrievedTSSIndex1], retrievedTSSIndex1).mul(retrievedTSS1)) + .umod(ecCurve.n); + const tssPubKey1 = ecCurve.keyFromPrivate(tssPrivKey1).getPublic(); + + const pubKey1 = tb1.getTSSPub(1); + strictEqual(tssPubKey1.x.toString(16, 64), pubKey1.x.toString(16, 64)); + strictEqual(tssPubKey1.y.toString(16, 64), pubKey1.y.toString(16, 64)); + + const factorKey1 = new BN(generatePrivate()); + const factorPub1 = getPubKeyPoint(factorKey1); + + const factorPubs1 = [factorPub, factorPub1]; + const { serverEndpoints, serverPubKeys } = await sp.getRSSNodeDetails(); + const { tssShare: retrievedTSSShare1, tssIndex: retrievedTSSIdx1 } = await tb1.getTSSShare(factorKey); + await tb1._refreshTSSShares(true, retrievedTSSShare1, retrievedTSSIdx1, factorPubs1, [2, 3], testId, { + serverThreshold: 3, + selectedServers: [1, 2, 3], + serverEndpoints, + serverPubKeys, + authSignatures: signatures, + }); const tb2 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); await tb2.initialize({ useTSS: true, factorPub }); await tb2.inputShareStoreSafe(newShare.newShareStores[newShare.newShareIndex.toString("hex")]); await tb2.reconstructKey(); - const { tssShare: retrievedTSS, tssIndex: retrievedTSSIndex } = await tb2.getTSSShare(factorKey); - const tssCommits = tb2.getTSSCommits(); - const tssPrivKey = getLagrangeCoeffs([1, retrievedTSSIndex], 1) - .mul(serverDKGPrivKeys[0]) - .add(getLagrangeCoeffs([1, retrievedTSSIndex], retrievedTSSIndex).mul(retrievedTSS)) + + const { tssShare: retrievedTSS2, tssIndex: retrievedTSSIndex2 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); + const tssPrivKey2 = getLagrangeCoeffs([1, retrievedTSSIndex2], 1) + .mul(serverDKGPrivKeys[0].add(tb1.computeNonce(2))) + .add(getLagrangeCoeffs([1, retrievedTSSIndex2], retrievedTSSIndex2).mul(retrievedTSS2)) .umod(ecCurve.n); - const tssPubKey = getPubKeyPoint(tssPrivKey); - strictEqual(tssPubKey.x.toString(16, 64), tssCommits[0].x.toString(16, 64)); - strictEqual(tssPubKey.y.toString(16, 64), tssCommits[0].y.toString(16, 64)); + const tssPubKey2 = getPubKeyPoint(tssPrivKey2); + const pubKey2 = tb1.getTSSPub(2); - // // test tss refresh + strictEqual(tssPubKey2.x.toString(16, 64), pubKey2.x.toString(16, 64)); + strictEqual(tssPubKey2.y.toString(16, 64), pubKey2.y.toString(16, 64)); + // // test tss refresh const factorKey2 = new BN(generatePrivate()); const factorPub2 = getPubKeyPoint(factorKey2); - const factorPubs = [factorPub, factorPub2]; - const { serverEndpoints, serverPubKeys } = await sp.getRSSNodeDetails(); - await tb2._refreshTSSShares(true, retrievedTSS, retrievedTSSIndex, factorPubs, [2, 3], testId, { + const factorPubs2 = [factorPub, factorPub2]; + const { tssShare: retrievedTSS3, tssIndex: retrievedTSSIndex3 } = await tb2.getTSSShare(factorKey); + await tb2._refreshTSSShares(true, retrievedTSS3, retrievedTSSIndex3, factorPubs2, [2, 3], testId, { serverThreshold: 3, selectedServers: [1, 2, 3], serverEndpoints, @@ -135,24 +165,70 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { authSignatures: signatures, }); + // test case to ensure nonce mechanism + { + notEqual(tssPubKey1.x.toString(16, 64), tssPubKey2.x.toString(16, 64)); + notEqual(tssPubKey1.y.toString(16, 64), tssPubKey2.y.toString(16, 64)); + + const { tssShare: retrievedTSS } = await tb2.getTSSShare(factorKey); + const tssSharePub = ecCurve.keyFromPrivate(retrievedTSS.toString("hex")).getPublic(); + const { tssShare: retrievedTSS2 } = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); + const tssSharePub2 = ecCurve.keyFromPrivate(retrievedTSS2.toString("hex")).getPublic(); + const nonce = tb1.computeNonce(1); + const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); + const tssShareDerived = tssSharePub.add(noncePub); + strictEqual(tssShareDerived.getX().toString("hex"), tssSharePub2.getX().toString("hex")); + strictEqual(tssShareDerived.getY().toString("hex"), tssSharePub2.getY().toString("hex")); + + const { tssShare: retrievedTSS3 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); + const tssSharePub3 = ecCurve.keyFromPrivate(retrievedTSS3.toString("hex")).getPublic(); + const nonce2 = tb1.computeNonce(2); + const noncePub2 = ecCurve.keyFromPrivate(nonce2.toString("hex")).getPublic(); + const tssShareDerived2 = tssSharePub.add(noncePub2); + strictEqual(tssShareDerived2.getX().toString("hex"), tssSharePub3.getX().toString("hex")); + strictEqual(tssShareDerived2.getY().toString("hex"), tssSharePub3.getY().toString("hex")); + } + { - const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey); + const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex")) - .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS2)) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeNonce(1))) + .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) .umod(ecCurve.n); - strictEqual(tssPrivKey.toString(16, 64), newTSSPrivKey.toString(16, 64)); + strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); + // eslint-disable-next-line no-console + console.log("newTSS", newTSS.toString("hex"), tssIndex); + } + + { + const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 1 }); + const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeNonce(1))) + .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) + .umod(ecCurve.n); + strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); // eslint-disable-next-line no-console console.log("newTSS2", newTSS2.toString("hex"), tssIndex); } { - const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2); + const { tssShare: newTSS, tssIndex } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); + const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb2.computeNonce(2))) + .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) + .umod(ecCurve.n); + strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); + // eslint-disable-next-line no-console + console.log("newTSS", newTSS.toString("hex"), tssIndex); + } + + { + const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 2 }); const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex")) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeNonce(2))) .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) .umod(ecCurve.n); - strictEqual(tssPrivKey.toString(16, 64), newTSSPrivKey.toString(16, 64)); + strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); // eslint-disable-next-line no-console console.log("newTSS2", newTSS2.toString("hex"), tssIndex); } @@ -252,7 +328,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { if (!sp.useTSS) this.skip(); // skip if not mock for now as we need to set key on server to test - if (!isMocked) this.skip(); + if (!isMocked) this(); const deviceTSSShare = new BN(generatePrivate()); const deviceTSSIndex = 3; @@ -365,7 +441,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { if (!sp.useTSS) this.skip(); // skip if not mock for now as we need to set key on server to test - if (!isMocked) this.skip(); + if (!isMocked) this(); const deviceTSSShare = new BN(generatePrivate()); const deviceTSSIndex = 3; @@ -691,7 +767,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { }); it(`#should be not be able to lookup delete share, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this.skip(); + if (!customSP.useTSS) this(); const newKeys = Object.keys(shareStoreAfterDelete); if (newKeys.find((el) => el === deletedShareIndex.toString("hex"))) { fail("Unable to delete share index"); @@ -702,7 +778,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { await tb.getTSSShare(newFactorKey); }); // it(`#should be able to delete a user and reset tss nonce, manualSync=${mode}`, async function () { - // if (!customSP.useTSS) this.skip(); + // if (!customSP.useTSS) this(); // // create 2/4 // await tb._initializeNewKey({ initializeModules: true }); // await tb.generateNewShare(); @@ -731,7 +807,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { // // TODO: check that TSS nonce is reset // }); it(`#should be able to reinitialize after wipe, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this.skip(); + if (!customSP.useTSS) this(); // create 2/4 const resp1 = await tb._initializeNewKey({ initializeModules: true }); await tb.generateNewShare(); @@ -765,7 +841,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { tb = new ThresholdKey({ serviceProvider: customSP, storageLayer: customSL, manualSync: mode }); }); it(`#should serialize and deserialize correctly without tkeyArgs, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this.skip(); + if (!customSP.useTSS) this(); const sp = customSP; let userInput = new BN(keccak256(Buffer.from("user answer blublu", "utf-8")).slice(2), "hex"); userInput = userInput.umod(ecCurve.curve.n); @@ -822,7 +898,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { strictEqual(tssPrivKey.toString("hex"), tssPrivKey2.toString("hex"), "Incorrect tss key"); }); it(`#should serialize and deserialize correctly with tkeyArgs, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this.skip(); + if (!customSP.useTSS) this(); let userInput = new BN(keccak256(Buffer.from("user answer blublu", "utf-8")).slice(2), "hex"); userInput = userInput.umod(ecCurve.curve.n); const resp1 = await tb._initializeNewKey({ userInput, initializeModules: true }); @@ -880,7 +956,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { }); // TODO: add test for initialize such that initialize throws if the remote metadata is already there it(`#should serialize and deserialize correctly, keeping localTransitions consistent before syncing NewKeyAssign, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this.skip(); + if (!customSP.useTSS) this(); const sp = customSP; sp.verifierName = "torus-test-health"; @@ -926,7 +1002,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { } }); it(`#should serialize and deserialize correctly keeping localTransitions afterNewKeyAssign, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this.skip(); + if (!customSP.useTSS) this(); let userInput = new BN(keccak256(Buffer.from("user answer blublu", "utf-8")).slice(2), "hex"); userInput = userInput.umod(ecCurve.curve.n); const resp1 = await tb._initializeNewKey({ userInput, initializeModules: true }); From 454e16481214e0504c664854b60d8c295016bf6e Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Wed, 7 Feb 2024 13:03:08 +0530 Subject: [PATCH 02/23] fix: edge cases --- packages/core/src/core.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index ca125b81e..20a852219 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -233,7 +233,7 @@ class ThresholdKey implements ITKey { if (!chainCode) { throw CoreError.default("chainCode is absent, required for nonce generation"); } - return new BN(keccak256(Buffer.from(`${index}${chainCode}`)).slice(2), "hex").umod(ecCurve.curve.n); + return index && index > 0 ? new BN(keccak256(Buffer.from(`${index}${chainCode}`)).slice(2), "hex").umod(ecCurve.curve.n) : new BN(0); } generateSalt(length = 32) { @@ -913,12 +913,15 @@ class ThresholdKey implements ITKey { serverEncs: refreshResponse.serverFactorEncs, }; } + const chainCode = this.generateSalt(); + this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: newTssNonce, tssPolyCommits: newTSSCommits, factorPubs, factorEncs, + chainCode, }); await this._syncShareMetadata(); } catch (error) { From 93e01ca68bb5a4e3659f844976c0a2c4db8d370c Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:28:19 +0530 Subject: [PATCH 03/23] fix: test cases --- packages/default/test/helpers.js | 3 --- packages/default/test/shared.js | 7 +++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/default/test/helpers.js b/packages/default/test/helpers.js index 210d978fd..bba6014f9 100644 --- a/packages/default/test/helpers.js +++ b/packages/default/test/helpers.js @@ -47,8 +47,6 @@ export function getServiceProvider(params) { // this url has no effect as postbox key is passed // passing it just to satisfy direct auth checks. baseUrl: "http://localhost:3000", - web3AuthClientId: "test", - network: "mainnet", }, }); } @@ -180,7 +178,6 @@ export async function assignTssDkgKeys(opts) { for (let j = 0; j < maxTSSNonceToSimulate; j++) { const token = generateIdToken(verifierId); const extendedVerifierId = `${verifierId}\u0015${tssTag}\u0016${j}`; - console.log("extendedVerifierId", extendedVerifierId); const { serverEndpoints: sssEndpoints } = await serviceProvider.getSSSNodeDetails(); const retrieveSharesResponse = await serviceProvider.customAuthInstance.torus.retrieveShares( diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index 156d40e05..aeddb7d31 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -637,6 +637,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { selectedServers: [1, 2, 3], serverEndpoints, serverPubKeys, + authSignatures: signatures, }); { @@ -849,7 +850,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { sp.verifierName = "torus-test-health"; sp.verifierId = "test18@example.com"; - const { postboxkey } = await fetchPostboxKeyAndSigs({ + const { postboxkey, signatures } = await fetchPostboxKeyAndSigs({ serviceProvider: sp, verifierName: sp.verifierName, verifierId: sp.verifierId, @@ -882,6 +883,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { inputTSSIndex: tssIndex, newFactorPub, newTSSIndex: 3, + authSignatures: signatures, }); await tb.syncLocalMetadataTransitions(); @@ -906,7 +908,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const sp = customSP; sp.verifierName = "torus-test-health"; sp.verifierId = "test18@example.com"; - const { postboxkey } = await fetchPostboxKeyAndSigs({ + const { postboxkey, signatures } = await fetchPostboxKeyAndSigs({ serviceProvider: sp, verifierName: sp.verifierName, verifierId: sp.verifierId, @@ -938,6 +940,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { inputTSSIndex: tssIndex, newFactorPub, newTSSIndex: 3, + authSignatures: signatures, }); await tb.syncLocalMetadataTransitions(); From a58413ffb3b55485d1fa4c44c978823126f0bccf Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:33:05 +0530 Subject: [PATCH 04/23] fix: test cases --- packages/default/test/tssTorusSPManualSync.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/default/test/tssTorusSPManualSync.test.js b/packages/default/test/tssTorusSPManualSync.test.js index b087f032f..c031e103b 100644 --- a/packages/default/test/tssTorusSPManualSync.test.js +++ b/packages/default/test/tssTorusSPManualSync.test.js @@ -30,7 +30,7 @@ const metadataURL = getMetadataUrl(); const torusSL = initStorageLayer({ hostUrl: metadataURL }); const MANUAL_SYNC = true; -describe.only(`TorusServiceProvider with manualSync: ${MANUAL_SYNC}`, function () { +describe(`TorusServiceProvider with manualSync: ${MANUAL_SYNC}`, function () { // eslint-disable-next-line mocha/no-setup-in-describe sharedTestCases(MANUAL_SYNC, torusSp, torusSL); }); From 01be6c2c8d5fe12024c03b5e0d252131e8c9ae42 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:38:19 +0530 Subject: [PATCH 05/23] fix: test cases --- .github/workflows/backward.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/backward.yml b/.github/workflows/backward.yml index 41670b680..0e22ad268 100644 --- a/.github/workflows/backward.yml +++ b/.github/workflows/backward.yml @@ -29,9 +29,9 @@ jobs: with: path: tkey - - name: switch path - run: | - cd ./tkey + # - name: switch path + # run: | + # cd ./tkey - name: Set up node uses: actions/setup-node@v3 From 970c5127ff702fb369f2ea18f6583977395a1b68 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:41:57 +0530 Subject: [PATCH 06/23] fix: test cases --- .github/workflows/backward.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backward.yml b/.github/workflows/backward.yml index 0e22ad268..9376e30b7 100644 --- a/.github/workflows/backward.yml +++ b/.github/workflows/backward.yml @@ -26,8 +26,8 @@ jobs: steps: - name: checkout tkey repo uses: actions/checkout@v3 - with: - path: tkey + # with: + # path: tkey # - name: switch path # run: | From e6d1daa7a56ce93c5fc43be14b0be4b7b10580ea Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:46:37 +0530 Subject: [PATCH 07/23] fix: test cases --- .github/workflows/backward.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backward.yml b/.github/workflows/backward.yml index 9376e30b7..0f50ed90d 100644 --- a/.github/workflows/backward.yml +++ b/.github/workflows/backward.yml @@ -54,7 +54,7 @@ jobs: run: | cd ./backward-compatibility-tests npm i - for filename in ../tkey/packages/* ; do + for filename in ../packages/* ; do echo "installing $filename" || continue # ... install packed packages packagename="`ls ${filename}| grep tkey`" From 2b982153f46a784f03b021ef5fb8ed120910c847 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:51:19 +0530 Subject: [PATCH 08/23] fix: test cases --- .github/workflows/backward.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/backward.yml b/.github/workflows/backward.yml index 0f50ed90d..0c1bef294 100644 --- a/.github/workflows/backward.yml +++ b/.github/workflows/backward.yml @@ -63,5 +63,4 @@ jobs: - name: Running comp tests run: | - cd ./backward-compatibility-tests npm test From b90f80f7a40ba69621e1a5cf09b3811b002e9d62 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:18:42 +0530 Subject: [PATCH 09/23] fix: test cases --- karmaBaseConfig.js | 6 +++--- packages/core/src/core.ts | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/karmaBaseConfig.js b/karmaBaseConfig.js index 1512ec4c3..183518fed 100644 --- a/karmaBaseConfig.js +++ b/karmaBaseConfig.js @@ -24,9 +24,9 @@ const localBrowserConfig = (webpackConfig, karmaConfig, packageConfig) => { frameworks: ["mocha", "webpack"], webpack: { - module: webpackConfig[1].module, - resolve: webpackConfig[1].resolve, - plugins: webpackConfig[1].plugins, + module: webpackConfig[0].module, + resolve: webpackConfig[0].resolve, + plugins: webpackConfig[0].plugins, }, plugins: ["karma-mocha-reporter", "karma-webkit-launcher", "karma-chrome-launcher", "karma-firefox-launcher", "karma-mocha", "karma-webpack"], diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 20a852219..e0db96544 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -54,7 +54,6 @@ import { import { generatePrivate } from "@toruslabs/eccrypto"; import { keccak256 } from "@toruslabs/torus.js"; import BN from "bn.js"; -import crypto from "crypto"; import stringify from "json-stable-stringify"; import AuthMetadata from "./authMetadata"; @@ -236,8 +235,8 @@ class ThresholdKey implements ITKey { return index && index > 0 ? new BN(keccak256(Buffer.from(`${index}${chainCode}`)).slice(2), "hex").umod(ecCurve.curve.n) : new BN(0); } - generateSalt(length = 32) { - return crypto.randomBytes(length).toString("hex"); + generateSalt() { + return generatePrivate().toString("hex"); } async initialize(params?: { From 50d9fb3f1c9b8270dd2fadaa86537805dc730a5d Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:25:30 +0530 Subject: [PATCH 10/23] fix: test cases --- packages/default/test/shared.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index aeddb7d31..2e4825cb5 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -328,7 +328,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { if (!sp.useTSS) this.skip(); // skip if not mock for now as we need to set key on server to test - if (!isMocked) this(); + if (!isMocked) this.skip(); const deviceTSSShare = new BN(generatePrivate()); const deviceTSSIndex = 3; From 3d242471d771c419ff17dd58750a5ec5738fa6ca Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Mon, 19 Feb 2024 10:07:15 +0530 Subject: [PATCH 11/23] fix: review comments --- package-lock.json | 9 +--- .../src/baseTypes/aggregateTypes.ts | 4 +- packages/common-types/src/utils.ts | 4 ++ packages/core/package.json | 1 - packages/core/src/core.ts | 54 +++++++++---------- packages/core/src/errors.ts | 5 ++ packages/core/src/metadata.ts | 16 +++--- packages/default/test/shared.js | 20 +++---- 8 files changed, 54 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index bd013d9a4..391074081 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8092,12 +8092,6 @@ "node": ">= 8" } }, - "node_modules/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", - "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in." - }, "node_modules/crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -24283,7 +24277,7 @@ }, "packages/core": { "name": "@tkey-mpc/core", - "version": "9.0.2", + "version": "9.0.3", "license": "MIT", "dependencies": { "@tkey-mpc/common-types": "^9.0.2", @@ -24292,7 +24286,6 @@ "@toruslabs/rss-client": "^1.5.0", "@toruslabs/torus.js": "^11.0.6", "bn.js": "^5.2.1", - "crypto": "^1.0.1", "elliptic": "^6.5.4", "json-stable-stringify": "^1.0.2" }, diff --git a/packages/common-types/src/baseTypes/aggregateTypes.ts b/packages/common-types/src/baseTypes/aggregateTypes.ts index 5b5937e04..af765d46f 100644 --- a/packages/common-types/src/baseTypes/aggregateTypes.ts +++ b/packages/common-types/src/baseTypes/aggregateTypes.ts @@ -79,7 +79,7 @@ export interface IMetadata extends ISerializable { nonce: number; - chainCode?: string; + accountSalt?: string; getShareIndexesForPolynomial(polyID: PolynomialID): string[]; getLatestPublicPolynomial(): PublicPolynomial; @@ -91,7 +91,7 @@ export interface IMetadata extends ISerializable { factorEncs?: { [factorPubID: string]: FactorEnc; }; - chainCode?: string; + accountSalt?: string; }): void; addPublicShare(polynomialID: PolynomialID, publicShare: PublicShare): void; setGeneralStoreDomain(key: string, obj: unknown): void; diff --git a/packages/common-types/src/utils.ts b/packages/common-types/src/utils.ts index f07a5ab85..1967563ac 100644 --- a/packages/common-types/src/utils.ts +++ b/packages/common-types/src/utils.ts @@ -104,3 +104,7 @@ export function generateID(): string { // after the decimal. return `${Math.random().toString(36).substr(2, 9)}`; } + +export function generateSalt() { + return generatePrivate().toString("hex").padStart(64, "0"); +} diff --git a/packages/core/package.json b/packages/core/package.json index e9d79bf15..05f692cd4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -40,7 +40,6 @@ "@toruslabs/rss-client": "^1.5.0", "@toruslabs/torus.js": "^11.0.6", "bn.js": "^5.2.1", - "crypto": "^1.0.1", "elliptic": "^6.5.4", "json-stable-stringify": "^1.0.2" }, diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index e0db96544..b321868a5 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -11,6 +11,7 @@ import { FromJSONConstructor, GenerateNewShareResult, generatePrivateExcludingIndexes, + generateSalt, getPubKeyECC, getPubKeyPoint, hexPoint, @@ -226,19 +227,6 @@ class ThresholdKey implements ITKey { throw CoreError.metadataUndefined(); } - computeNonce(index: number) { - // generation should occur during tkey.init, fails if chaincode is absent - const { chainCode } = this.metadata; - if (!chainCode) { - throw CoreError.default("chainCode is absent, required for nonce generation"); - } - return index && index > 0 ? new BN(keccak256(Buffer.from(`${index}${chainCode}`)).slice(2), "hex").umod(ecCurve.curve.n) : new BN(0); - } - - generateSalt() { - return generatePrivate().toString("hex"); - } - async initialize(params?: { withShare?: ShareStore; importKey?: BN; @@ -313,8 +301,8 @@ class ThresholdKey implements ITKey { }); if (useTSS) { const { factorEncs, factorPubs, tssPolyCommits } = await this._initializeNewTSSKey(this.tssTag, deviceTSSShare, factorPub, deviceTSSIndex); - const chainCode = this.generateSalt(); - this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: 0, tssPolyCommits, factorPubs, factorEncs, chainCode }); + const accountSalt = generateSalt(); + this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: 0, tssPolyCommits, factorPubs, factorEncs, accountSalt }); } return this.getKeyDetails(); } @@ -432,7 +420,7 @@ class ThresholdKey implements ITKey { } if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { if (accountIndex && accountIndex > 0) { - const nonce = this.computeNonce(accountIndex); + const nonce = this.computeAccountNonce(accountIndex); const derivedShare = userDec.add(nonce).umod(ecCurve.n); return { tssIndex, tssShare: derivedShare }; } @@ -463,15 +451,12 @@ class ThresholdKey implements ITKey { for (let j = 0; j < tssIndex; j++) { _tssSharePub = _tssSharePub.add(tssCommitA1); } - if (accountIndex && accountIndex > 0) { - const nonce = this.computeNonce(accountIndex); - const derivedShare = tssShare.add(nonce).umod(ecCurve.n); - if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { + if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { + if (accountIndex && accountIndex > 0) { + const nonce = this.computeAccountNonce(accountIndex); + const derivedShare = tssShare.add(nonce).umod(ecCurve.n); return { tssIndex, tssShare: derivedShare }; } - } - - if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { return { tssIndex, tssShare }; } } @@ -488,17 +473,16 @@ class ThresholdKey implements ITKey { } getTSSPub(accountIndex?: number): Point { + const tssCommits = this.getTSSCommits(); if (accountIndex && accountIndex > 0) { - const nonce = this.computeNonce(accountIndex); + const nonce = this.computeAccountNonce(accountIndex); // we need to add the pub key nonce to the tssPub const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); - const pubKeyPoint = ecCurve - .keyFromPublic({ x: this.getTSSCommits()[0].x.toString("hex"), y: this.getTSSCommits()[0].y.toString("hex") }) - .getPublic(); + const pubKeyPoint = ecCurve.keyFromPublic({ x: tssCommits[0].x.toString("hex"), y: tssCommits[0].y.toString("hex") }).getPublic(); const dervicepubKeyPoint = pubKeyPoint.add(noncePub); return new Point(dervicepubKeyPoint.getX().toString("hex"), dervicepubKeyPoint.getY().toString("hex")); } - return this.getTSSCommits()[0]; + return tssCommits[0]; } /** @@ -912,7 +896,7 @@ class ThresholdKey implements ITKey { serverEncs: refreshResponse.serverFactorEncs, }; } - const chainCode = this.generateSalt(); + const accountSalt = generateSalt(); this.metadata.addTSSData({ tssTag: this.tssTag, @@ -920,7 +904,7 @@ class ThresholdKey implements ITKey { tssPolyCommits: newTSSCommits, factorPubs, factorEncs, - chainCode, + accountSalt, }); await this._syncShareMetadata(); } catch (error) { @@ -2007,6 +1991,16 @@ class ThresholdKey implements ITKey { private async initializeModules() { return Promise.all(Object.keys(this.modules).map((x) => this.modules[x].initialize())); } + + private computeAccountNonce(index: number) { + // generation should occur during tkey.init, fails if accountSalt is absent + const { accountSalt } = this.metadata; + if (!accountSalt) { + throw CoreError.accountSaltUndefined(); + } + const accountHash = keccak256(Buffer.from(`${index}${accountSalt}`)).slice(2); + return index && index > 0 ? new BN(accountHash, "hex").umod(ecCurve.curve.n) : new BN(0); + } } export default ThresholdKey; diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index 38137f8ac..fdbf5c00a 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -32,6 +32,7 @@ class CoreError extends TkeyError { 1103: "setMetadata errored", 1104: "previouslyFetchedCloudMetadata provided in initialization is outdated", 1105: "previouslyFetchedCloudMetadata.nonce should never be higher than the latestShareDetails, please contact support", + 1106: "Account Salt is absent, required for nonce generation", // tkeystore 1201: "Invalid tkeyStore", 1202: "Encryption failed", @@ -90,6 +91,10 @@ class CoreError extends TkeyError { return CoreError.fromCode(1103, extraMessage); } + public static accountSaltUndefined(extraMessage = ""): ITkeyError { + return CoreError.fromCode(1106, extraMessage); + } + // TkeyData public static tkeyStoreInvalid(extraMessage = ""): ITkeyError { return CoreError.fromCode(1201, extraMessage); diff --git a/packages/core/src/metadata.ts b/packages/core/src/metadata.ts index 5adc27961..a1158d61a 100644 --- a/packages/core/src/metadata.ts +++ b/packages/core/src/metadata.ts @@ -69,7 +69,7 @@ class Metadata implements IMetadata { }; // salt - chainCode?: string; + accountSalt?: string; constructor(input: Point) { this.tssPolyCommits = {}; @@ -87,7 +87,7 @@ class Metadata implements IMetadata { } static fromJSON(value: StringifiedType): Metadata { - const { pubKey, polyIDList, generalStore, tkeyStore, scopedStore, nonce, tssNonces, tssPolyCommits, factorPubs, factorEncs, chainCode } = value; + const { pubKey, polyIDList, generalStore, tkeyStore, scopedStore, nonce, tssNonces, tssPolyCommits, factorPubs, factorEncs, accountSalt } = value; const point = Point.fromCompressedPub(pubKey); const metadata = new Metadata(point); const unserializedPolyIDList: PolyIDAndShares[] = []; @@ -96,7 +96,7 @@ class Metadata implements IMetadata { if (tkeyStore) metadata.tkeyStore = tkeyStore; if (scopedStore) metadata.scopedStore = scopedStore; if (nonce) metadata.nonce = nonce; - if (chainCode) metadata.chainCode = chainCode; + if (accountSalt) metadata.accountSalt = accountSalt; if (tssPolyCommits) { metadata.tssPolyCommits = {}; for (const key in tssPolyCommits) { @@ -194,15 +194,15 @@ class Metadata implements IMetadata { factorEncs?: { [factorPubID: string]: FactorEnc; }; - chainCode?: string; + accountSalt?: string; }): void { - const { tssTag, tssNonce, tssPolyCommits, factorPubs, factorEncs, chainCode } = tssData; + const { tssTag, tssNonce, tssPolyCommits, factorPubs, factorEncs, accountSalt } = tssData; if (tssNonce !== undefined) this.tssNonces[tssTag] = tssNonce; if (tssPolyCommits) this.tssPolyCommits[tssTag] = tssPolyCommits; if (factorPubs) this.factorPubs[tssTag] = factorPubs; if (factorEncs) this.factorEncs[tssTag] = factorEncs; - if (chainCode && !this.chainCode) { - this.chainCode = chainCode; + if (accountSalt && !this.accountSalt) { + this.accountSalt = accountSalt; } } @@ -347,7 +347,7 @@ class Metadata implements IMetadata { ...(this.tssPolyCommits && { tssPolyCommits: this.tssPolyCommits }), ...(this.factorPubs && { factorPubs: this.factorPubs }), ...(this.factorEncs && { factorEncs: this.factorEncs }), - ...(this.chainCode && { chainCode: this.chainCode }), + ...(this.accountSalt && { accountSalt: this.accountSalt }), }; } } diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index 2e4825cb5..81b21c705 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -93,10 +93,10 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const storageLayer = initStorageLayer({ hostUrl: metadataURL }); const tb1 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); - // chainCode is absent, required for nonce generation + // accountSalt is absent, required for nonce generation // can be only initialize with tkey.initialize(); rejects(async () => { - await tb1.computeNonce(1); + await tb1.computeAccountNonce(1); }); // factor key needs to passed from outside of tKey const factorKey = new BN(generatePrivate()); @@ -111,7 +111,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { } const { tssShare: retrievedTSS1, tssIndex: retrievedTSSIndex1 } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const tssPrivKey1 = getLagrangeCoeffs([1, retrievedTSSIndex1], 1) - .mul(serverDKGPrivKeys[0].add(tb1.computeNonce(1))) + .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, retrievedTSSIndex1], retrievedTSSIndex1).mul(retrievedTSS1)) .umod(ecCurve.n); const tssPubKey1 = ecCurve.keyFromPrivate(tssPrivKey1).getPublic(); @@ -141,7 +141,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const { tssShare: retrievedTSS2, tssIndex: retrievedTSSIndex2 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const tssPrivKey2 = getLagrangeCoeffs([1, retrievedTSSIndex2], 1) - .mul(serverDKGPrivKeys[0].add(tb1.computeNonce(2))) + .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, retrievedTSSIndex2], retrievedTSSIndex2).mul(retrievedTSS2)) .umod(ecCurve.n); @@ -174,7 +174,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const tssSharePub = ecCurve.keyFromPrivate(retrievedTSS.toString("hex")).getPublic(); const { tssShare: retrievedTSS2 } = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); const tssSharePub2 = ecCurve.keyFromPrivate(retrievedTSS2.toString("hex")).getPublic(); - const nonce = tb1.computeNonce(1); + const nonce = tb1.computeAccountNonce(1); const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); const tssShareDerived = tssSharePub.add(noncePub); strictEqual(tssShareDerived.getX().toString("hex"), tssSharePub2.getX().toString("hex")); @@ -182,7 +182,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const { tssShare: retrievedTSS3 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const tssSharePub3 = ecCurve.keyFromPrivate(retrievedTSS3.toString("hex")).getPublic(); - const nonce2 = tb1.computeNonce(2); + const nonce2 = tb1.computeAccountNonce(2); const noncePub2 = ecCurve.keyFromPrivate(nonce2.toString("hex")).getPublic(); const tssShareDerived2 = tssSharePub.add(noncePub2); strictEqual(tssShareDerived2.getX().toString("hex"), tssSharePub3.getX().toString("hex")); @@ -192,7 +192,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeNonce(1))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) .umod(ecCurve.n); strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -203,7 +203,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 1 }); const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeNonce(1))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) .umod(ecCurve.n); strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -214,7 +214,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS, tssIndex } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb2.computeNonce(2))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb2.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) .umod(ecCurve.n); strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -225,7 +225,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 2 }); const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeNonce(2))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) .umod(ecCurve.n); strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); From 3d885596828fb9d375bccd7e48eee9610629971d Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Mon, 19 Feb 2024 10:12:28 +0530 Subject: [PATCH 12/23] fix: review comments --- packages/default/test/shared.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index 81b21c705..a76f3084f 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -768,7 +768,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { }); it(`#should be not be able to lookup delete share, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this(); + if (!customSP.useTSS) this.skip(); const newKeys = Object.keys(shareStoreAfterDelete); if (newKeys.find((el) => el === deletedShareIndex.toString("hex"))) { fail("Unable to delete share index"); @@ -808,7 +808,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { // // TODO: check that TSS nonce is reset // }); it(`#should be able to reinitialize after wipe, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this(); + if (!customSP.useTSS) this.skip(); // create 2/4 const resp1 = await tb._initializeNewKey({ initializeModules: true }); await tb.generateNewShare(); @@ -842,7 +842,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { tb = new ThresholdKey({ serviceProvider: customSP, storageLayer: customSL, manualSync: mode }); }); it(`#should serialize and deserialize correctly without tkeyArgs, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this(); + if (!customSP.useTSS) this.skip(); const sp = customSP; let userInput = new BN(keccak256(Buffer.from("user answer blublu", "utf-8")).slice(2), "hex"); userInput = userInput.umod(ecCurve.curve.n); @@ -900,7 +900,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { strictEqual(tssPrivKey.toString("hex"), tssPrivKey2.toString("hex"), "Incorrect tss key"); }); it(`#should serialize and deserialize correctly with tkeyArgs, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this(); + if (!customSP.useTSS) this.skip(); let userInput = new BN(keccak256(Buffer.from("user answer blublu", "utf-8")).slice(2), "hex"); userInput = userInput.umod(ecCurve.curve.n); const resp1 = await tb._initializeNewKey({ userInput, initializeModules: true }); @@ -959,7 +959,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { }); // TODO: add test for initialize such that initialize throws if the remote metadata is already there it(`#should serialize and deserialize correctly, keeping localTransitions consistent before syncing NewKeyAssign, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this(); + if (!customSP.useTSS) this.skip(); const sp = customSP; sp.verifierName = "torus-test-health"; @@ -1005,7 +1005,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { } }); it(`#should serialize and deserialize correctly keeping localTransitions afterNewKeyAssign, manualSync=${mode}`, async function () { - if (!customSP.useTSS) this(); + if (!customSP.useTSS) this.skip(); let userInput = new BN(keccak256(Buffer.from("user answer blublu", "utf-8")).slice(2), "hex"); userInput = userInput.umod(ecCurve.curve.n); const resp1 = await tb._initializeNewKey({ userInput, initializeModules: true }); From 3a2f2af17630829422efc0fa2628e446742a1ba1 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:12:06 +0530 Subject: [PATCH 13/23] feat: tkey store domain --- .../src/baseTypes/aggregateTypes.ts | 1 + packages/core/src/core.ts | 31 ++++++++++++------- packages/core/src/metadata.ts | 13 ++------ packages/default/test/shared.js | 20 ++++++------ 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/packages/common-types/src/baseTypes/aggregateTypes.ts b/packages/common-types/src/baseTypes/aggregateTypes.ts index af765d46f..96b73b2bc 100644 --- a/packages/common-types/src/baseTypes/aggregateTypes.ts +++ b/packages/common-types/src/baseTypes/aggregateTypes.ts @@ -199,6 +199,7 @@ export interface ShareRequestArgs { export type TkeyStoreItemType = { id: string; + value?: string; }; export type ISeedPhraseStore = TkeyStoreItemType & { diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index b321868a5..7ffe18651 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -69,6 +69,7 @@ import { } from "./lagrangeInterpolatePolynomial"; import Metadata from "./metadata"; // TODO: handle errors for get and set with retries +export const TSS_MODULE = "tssModule"; class ThresholdKey implements ITKey { modules: ModuleMap; @@ -99,6 +100,8 @@ class ThresholdKey implements ITKey { _shareSerializationMiddleware: ShareSerializationMiddleware; + _accountSalt: string; + storeDeviceShare: (deviceShareStore: ShareStore, customDeviceInfo?: StringifiedType) => Promise; haveWriteMetadataLock: string; @@ -302,7 +305,11 @@ class ThresholdKey implements ITKey { if (useTSS) { const { factorEncs, factorPubs, tssPolyCommits } = await this._initializeNewTSSKey(this.tssTag, deviceTSSShare, factorPub, deviceTSSIndex); const accountSalt = generateSalt(); - this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: 0, tssPolyCommits, factorPubs, factorEncs, accountSalt }); + this._setTKeyStoreItem(TSS_MODULE, { + id: "accountSalt", + value: accountSalt, + }); + this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: 0, tssPolyCommits, factorPubs, factorEncs }); } return this.getKeyDetails(); } @@ -420,7 +427,7 @@ class ThresholdKey implements ITKey { } if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { if (accountIndex && accountIndex > 0) { - const nonce = this.computeAccountNonce(accountIndex); + const nonce = await this.computeAccountNonce(accountIndex); const derivedShare = userDec.add(nonce).umod(ecCurve.n); return { tssIndex, tssShare: derivedShare }; } @@ -453,7 +460,7 @@ class ThresholdKey implements ITKey { } if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { if (accountIndex && accountIndex > 0) { - const nonce = this.computeAccountNonce(accountIndex); + const nonce = await this.computeAccountNonce(accountIndex); const derivedShare = tssShare.add(nonce).umod(ecCurve.n); return { tssIndex, tssShare: derivedShare }; } @@ -472,10 +479,10 @@ class ThresholdKey implements ITKey { return tssPolyCommits; } - getTSSPub(accountIndex?: number): Point { + async getTSSPub(accountIndex?: number): Promise { const tssCommits = this.getTSSCommits(); if (accountIndex && accountIndex > 0) { - const nonce = this.computeAccountNonce(accountIndex); + const nonce = await this.computeAccountNonce(accountIndex); // we need to add the pub key nonce to the tssPub const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); const pubKeyPoint = ecCurve.keyFromPublic({ x: tssCommits[0].x.toString("hex"), y: tssCommits[0].y.toString("hex") }).getPublic(); @@ -897,14 +904,16 @@ class ThresholdKey implements ITKey { }; } const accountSalt = generateSalt(); - this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: newTssNonce, tssPolyCommits: newTSSCommits, factorPubs, factorEncs, - accountSalt, + }); + this._setTKeyStoreItem(TSS_MODULE, { + id: "accountSalt", + value: accountSalt, }); await this._syncShareMetadata(); } catch (error) { @@ -1992,13 +2001,13 @@ class ThresholdKey implements ITKey { return Promise.all(Object.keys(this.modules).map((x) => this.modules[x].initialize())); } - private computeAccountNonce(index: number) { + private async computeAccountNonce(index: number) { // generation should occur during tkey.init, fails if accountSalt is absent - const { accountSalt } = this.metadata; - if (!accountSalt) { + this._accountSalt = this._accountSalt || (await this.getTKeyStoreItem(TSS_MODULE, "accountSalt")).value; + if (!this._accountSalt) { throw CoreError.accountSaltUndefined(); } - const accountHash = keccak256(Buffer.from(`${index}${accountSalt}`)).slice(2); + const accountHash = keccak256(Buffer.from(`${index}${this._accountSalt}`)).slice(2); return index && index > 0 ? new BN(accountHash, "hex").umod(ecCurve.curve.n) : new BN(0); } } diff --git a/packages/core/src/metadata.ts b/packages/core/src/metadata.ts index a1158d61a..c2222e239 100644 --- a/packages/core/src/metadata.ts +++ b/packages/core/src/metadata.ts @@ -68,9 +68,6 @@ class Metadata implements IMetadata { }; }; - // salt - accountSalt?: string; - constructor(input: Point) { this.tssPolyCommits = {}; this.tssNonces = {}; @@ -87,7 +84,7 @@ class Metadata implements IMetadata { } static fromJSON(value: StringifiedType): Metadata { - const { pubKey, polyIDList, generalStore, tkeyStore, scopedStore, nonce, tssNonces, tssPolyCommits, factorPubs, factorEncs, accountSalt } = value; + const { pubKey, polyIDList, generalStore, tkeyStore, scopedStore, nonce, tssNonces, tssPolyCommits, factorPubs, factorEncs } = value; const point = Point.fromCompressedPub(pubKey); const metadata = new Metadata(point); const unserializedPolyIDList: PolyIDAndShares[] = []; @@ -96,7 +93,6 @@ class Metadata implements IMetadata { if (tkeyStore) metadata.tkeyStore = tkeyStore; if (scopedStore) metadata.scopedStore = scopedStore; if (nonce) metadata.nonce = nonce; - if (accountSalt) metadata.accountSalt = accountSalt; if (tssPolyCommits) { metadata.tssPolyCommits = {}; for (const key in tssPolyCommits) { @@ -194,16 +190,12 @@ class Metadata implements IMetadata { factorEncs?: { [factorPubID: string]: FactorEnc; }; - accountSalt?: string; }): void { - const { tssTag, tssNonce, tssPolyCommits, factorPubs, factorEncs, accountSalt } = tssData; + const { tssTag, tssNonce, tssPolyCommits, factorPubs, factorEncs } = tssData; if (tssNonce !== undefined) this.tssNonces[tssTag] = tssNonce; if (tssPolyCommits) this.tssPolyCommits[tssTag] = tssPolyCommits; if (factorPubs) this.factorPubs[tssTag] = factorPubs; if (factorEncs) this.factorEncs[tssTag] = factorEncs; - if (accountSalt && !this.accountSalt) { - this.accountSalt = accountSalt; - } } // appends shares and public polynomial to metadata. @@ -347,7 +339,6 @@ class Metadata implements IMetadata { ...(this.tssPolyCommits && { tssPolyCommits: this.tssPolyCommits }), ...(this.factorPubs && { factorPubs: this.factorPubs }), ...(this.factorEncs && { factorEncs: this.factorEncs }), - ...(this.accountSalt && { accountSalt: this.accountSalt }), }; } } diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index a76f3084f..59854753f 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -111,12 +111,12 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { } const { tssShare: retrievedTSS1, tssIndex: retrievedTSSIndex1 } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const tssPrivKey1 = getLagrangeCoeffs([1, retrievedTSSIndex1], 1) - .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(1))) + .mul(serverDKGPrivKeys[0].add(await tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, retrievedTSSIndex1], retrievedTSSIndex1).mul(retrievedTSS1)) .umod(ecCurve.n); const tssPubKey1 = ecCurve.keyFromPrivate(tssPrivKey1).getPublic(); - const pubKey1 = tb1.getTSSPub(1); + const pubKey1 = await tb1.getTSSPub(1); strictEqual(tssPubKey1.x.toString(16, 64), pubKey1.x.toString(16, 64)); strictEqual(tssPubKey1.y.toString(16, 64), pubKey1.y.toString(16, 64)); @@ -141,12 +141,12 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const { tssShare: retrievedTSS2, tssIndex: retrievedTSSIndex2 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const tssPrivKey2 = getLagrangeCoeffs([1, retrievedTSSIndex2], 1) - .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(2))) + .mul(serverDKGPrivKeys[0].add(await tb1.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, retrievedTSSIndex2], retrievedTSSIndex2).mul(retrievedTSS2)) .umod(ecCurve.n); const tssPubKey2 = getPubKeyPoint(tssPrivKey2); - const pubKey2 = tb1.getTSSPub(2); + const pubKey2 = await tb1.getTSSPub(2); strictEqual(tssPubKey2.x.toString(16, 64), pubKey2.x.toString(16, 64)); strictEqual(tssPubKey2.y.toString(16, 64), pubKey2.y.toString(16, 64)); @@ -174,7 +174,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const tssSharePub = ecCurve.keyFromPrivate(retrievedTSS.toString("hex")).getPublic(); const { tssShare: retrievedTSS2 } = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); const tssSharePub2 = ecCurve.keyFromPrivate(retrievedTSS2.toString("hex")).getPublic(); - const nonce = tb1.computeAccountNonce(1); + const nonce = await tb1.computeAccountNonce(1); const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); const tssShareDerived = tssSharePub.add(noncePub); strictEqual(tssShareDerived.getX().toString("hex"), tssSharePub2.getX().toString("hex")); @@ -182,7 +182,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const { tssShare: retrievedTSS3 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const tssSharePub3 = ecCurve.keyFromPrivate(retrievedTSS3.toString("hex")).getPublic(); - const nonce2 = tb1.computeAccountNonce(2); + const nonce2 = await tb1.computeAccountNonce(2); const noncePub2 = ecCurve.keyFromPrivate(nonce2.toString("hex")).getPublic(); const tssShareDerived2 = tssSharePub.add(noncePub2); strictEqual(tssShareDerived2.getX().toString("hex"), tssSharePub3.getX().toString("hex")); @@ -192,7 +192,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) .umod(ecCurve.n); strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -203,7 +203,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 1 }); const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) .umod(ecCurve.n); strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -214,7 +214,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS, tssIndex } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb2.computeAccountNonce(2))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb2.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) .umod(ecCurve.n); strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -225,7 +225,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 2 }); const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(2))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb1.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) .umod(ecCurve.n); strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); From e0f3ba4b91047dbce62fc15d786bd1fa90e254d3 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:16:04 +0530 Subject: [PATCH 14/23] fix: cleanup --- packages/common-types/src/baseTypes/aggregateTypes.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/common-types/src/baseTypes/aggregateTypes.ts b/packages/common-types/src/baseTypes/aggregateTypes.ts index 96b73b2bc..2e94ec905 100644 --- a/packages/common-types/src/baseTypes/aggregateTypes.ts +++ b/packages/common-types/src/baseTypes/aggregateTypes.ts @@ -79,8 +79,6 @@ export interface IMetadata extends ISerializable { nonce: number; - accountSalt?: string; - getShareIndexesForPolynomial(polyID: PolynomialID): string[]; getLatestPublicPolynomial(): PublicPolynomial; addTSSData(tssData: { @@ -91,7 +89,6 @@ export interface IMetadata extends ISerializable { factorEncs?: { [factorPubID: string]: FactorEnc; }; - accountSalt?: string; }): void; addPublicShare(polynomialID: PolynomialID, publicShare: PublicShare): void; setGeneralStoreDomain(key: string, obj: unknown): void; From 312e06537362755a12111ec4f053bf79004ee216 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:22:36 +0530 Subject: [PATCH 15/23] fix: cleanup --- packages/default/test/shared.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index 59854753f..e64be869a 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -441,7 +441,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { if (!sp.useTSS) this.skip(); // skip if not mock for now as we need to set key on server to test - if (!isMocked) this(); + if (!isMocked) this.skip(); const deviceTSSShare = new BN(generatePrivate()); const deviceTSSIndex = 3; From 19f276dc2d19208793806f1a6e8a2dee77ec7e85 Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Tue, 20 Feb 2024 17:31:57 +0530 Subject: [PATCH 16/23] fix: review comments --- packages/core/src/core.ts | 13 ++++++++----- packages/core/src/errors.ts | 4 ++-- packages/default/test/shared.js | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 7ffe18651..d00ebe0f6 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -479,17 +479,16 @@ class ThresholdKey implements ITKey { return tssPolyCommits; } - async getTSSPub(accountIndex?: number): Promise { + getTSSPub(accountIndex?: number): Point { const tssCommits = this.getTSSCommits(); if (accountIndex && accountIndex > 0) { - const nonce = await this.computeAccountNonce(accountIndex); + const nonce = this.computeAccountNonce(accountIndex); // we need to add the pub key nonce to the tssPub const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); const pubKeyPoint = ecCurve.keyFromPublic({ x: tssCommits[0].x.toString("hex"), y: tssCommits[0].y.toString("hex") }).getPublic(); const dervicepubKeyPoint = pubKeyPoint.add(noncePub); return new Point(dervicepubKeyPoint.getX().toString("hex"), dervicepubKeyPoint.getY().toString("hex")); } - return tssCommits[0]; } /** @@ -620,6 +619,11 @@ class ThresholdKey implements ITKey { }) ); } + + // assign account salt from tKey store if it exists + const accountSalt = await this.getTKeyStoreItem(TSS_MODULE, "accountSalt"); + if (accountSalt && accountSalt?.value) this._accountSalt = accountSalt.value; + return { privKey, ...returnObject }; } @@ -2001,9 +2005,8 @@ class ThresholdKey implements ITKey { return Promise.all(Object.keys(this.modules).map((x) => this.modules[x].initialize())); } - private async computeAccountNonce(index: number) { + private computeAccountNonce(index: number) { // generation should occur during tkey.init, fails if accountSalt is absent - this._accountSalt = this._accountSalt || (await this.getTKeyStoreItem(TSS_MODULE, "accountSalt")).value; if (!this._accountSalt) { throw CoreError.accountSaltUndefined(); } diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index fdbf5c00a..03dab9f1c 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -32,8 +32,8 @@ class CoreError extends TkeyError { 1103: "setMetadata errored", 1104: "previouslyFetchedCloudMetadata provided in initialization is outdated", 1105: "previouslyFetchedCloudMetadata.nonce should never be higher than the latestShareDetails, please contact support", - 1106: "Account Salt is absent, required for nonce generation", - // tkeystore + 1106: "Account Salt is absent, required for nonce generation.Make sure key is reconstructed", + // tKeystore 1201: "Invalid tkeyStore", 1202: "Encryption failed", 1203: "Decryption failed", diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index e64be869a..ec2d28c15 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -96,7 +96,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { // accountSalt is absent, required for nonce generation // can be only initialize with tkey.initialize(); rejects(async () => { - await tb1.computeAccountNonce(1); + tb1.computeAccountNonce(1); }); // factor key needs to passed from outside of tKey const factorKey = new BN(generatePrivate()); @@ -111,12 +111,12 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { } const { tssShare: retrievedTSS1, tssIndex: retrievedTSSIndex1 } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const tssPrivKey1 = getLagrangeCoeffs([1, retrievedTSSIndex1], 1) - .mul(serverDKGPrivKeys[0].add(await tb1.computeAccountNonce(1))) + .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, retrievedTSSIndex1], retrievedTSSIndex1).mul(retrievedTSS1)) .umod(ecCurve.n); const tssPubKey1 = ecCurve.keyFromPrivate(tssPrivKey1).getPublic(); - const pubKey1 = await tb1.getTSSPub(1); + const pubKey1 = tb1.getTSSPub(1); strictEqual(tssPubKey1.x.toString(16, 64), pubKey1.x.toString(16, 64)); strictEqual(tssPubKey1.y.toString(16, 64), pubKey1.y.toString(16, 64)); @@ -141,12 +141,12 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const { tssShare: retrievedTSS2, tssIndex: retrievedTSSIndex2 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const tssPrivKey2 = getLagrangeCoeffs([1, retrievedTSSIndex2], 1) - .mul(serverDKGPrivKeys[0].add(await tb1.computeAccountNonce(2))) + .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, retrievedTSSIndex2], retrievedTSSIndex2).mul(retrievedTSS2)) .umod(ecCurve.n); const tssPubKey2 = getPubKeyPoint(tssPrivKey2); - const pubKey2 = await tb1.getTSSPub(2); + const pubKey2 = tb1.getTSSPub(2); strictEqual(tssPubKey2.x.toString(16, 64), pubKey2.x.toString(16, 64)); strictEqual(tssPubKey2.y.toString(16, 64), pubKey2.y.toString(16, 64)); @@ -174,7 +174,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const tssSharePub = ecCurve.keyFromPrivate(retrievedTSS.toString("hex")).getPublic(); const { tssShare: retrievedTSS2 } = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); const tssSharePub2 = ecCurve.keyFromPrivate(retrievedTSS2.toString("hex")).getPublic(); - const nonce = await tb1.computeAccountNonce(1); + const nonce = tb1.computeAccountNonce(1); const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); const tssShareDerived = tssSharePub.add(noncePub); strictEqual(tssShareDerived.getX().toString("hex"), tssSharePub2.getX().toString("hex")); @@ -182,7 +182,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { const { tssShare: retrievedTSS3 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const tssSharePub3 = ecCurve.keyFromPrivate(retrievedTSS3.toString("hex")).getPublic(); - const nonce2 = await tb1.computeAccountNonce(2); + const nonce2 = tb1.computeAccountNonce(2); const noncePub2 = ecCurve.keyFromPrivate(nonce2.toString("hex")).getPublic(); const tssShareDerived2 = tssSharePub.add(noncePub2); strictEqual(tssShareDerived2.getX().toString("hex"), tssSharePub3.getX().toString("hex")); @@ -192,7 +192,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb1.computeAccountNonce(1))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) .umod(ecCurve.n); strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -203,7 +203,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 1 }); const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb1.computeAccountNonce(1))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) .umod(ecCurve.n); strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -214,7 +214,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS, tssIndex } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb2.computeAccountNonce(2))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb2.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) .umod(ecCurve.n); strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); @@ -225,7 +225,7 @@ export const sharedTestCases = (mode, torusSP, storageLayer) => { { const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 2 }); const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(await tb1.computeAccountNonce(2))) + .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(2))) .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) .umod(ecCurve.n); strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); From a8443887333ddf71fa92ad2225b8089f0a01be9f Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Tue, 20 Feb 2024 19:29:32 +0530 Subject: [PATCH 17/23] fix: minor cleanup --- packages/core/src/core.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index d00ebe0f6..eb85b63e1 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -427,7 +427,7 @@ class ThresholdKey implements ITKey { } if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { if (accountIndex && accountIndex > 0) { - const nonce = await this.computeAccountNonce(accountIndex); + const nonce = this.computeAccountNonce(accountIndex); const derivedShare = userDec.add(nonce).umod(ecCurve.n); return { tssIndex, tssShare: derivedShare }; } @@ -460,7 +460,7 @@ class ThresholdKey implements ITKey { } if (tssSharePub.getX().cmp(_tssSharePub.getX()) === 0 && tssSharePub.getY().cmp(_tssSharePub.getY()) === 0) { if (accountIndex && accountIndex > 0) { - const nonce = await this.computeAccountNonce(accountIndex); + const nonce = this.computeAccountNonce(accountIndex); const derivedShare = tssShare.add(nonce).umod(ecCurve.n); return { tssIndex, tssShare: derivedShare }; } @@ -489,6 +489,7 @@ class ThresholdKey implements ITKey { const dervicepubKeyPoint = pubKeyPoint.add(noncePub); return new Point(dervicepubKeyPoint.getX().toString("hex"), dervicepubKeyPoint.getY().toString("hex")); } + return tssCommits[0]; } /** @@ -1969,6 +1970,15 @@ class ThresholdKey implements ITKey { this.lastFetchedCloudMetadata = undefined; } + computeAccountNonce(index: number) { + // generation should occur during tkey.init, fails if accountSalt is absent + if (!this._accountSalt) { + throw CoreError.accountSaltUndefined(); + } + const accountHash = keccak256(Buffer.from(`${index}${this._accountSalt}`)).slice(2); + return index && index > 0 ? new BN(accountHash, "hex").umod(ecCurve.curve.n) : new BN(0); + } + getApi(): ITKeyApi { return { getMetadata: this.getMetadata.bind(this), @@ -2004,15 +2014,6 @@ class ThresholdKey implements ITKey { private async initializeModules() { return Promise.all(Object.keys(this.modules).map((x) => this.modules[x].initialize())); } - - private computeAccountNonce(index: number) { - // generation should occur during tkey.init, fails if accountSalt is absent - if (!this._accountSalt) { - throw CoreError.accountSaltUndefined(); - } - const accountHash = keccak256(Buffer.from(`${index}${this._accountSalt}`)).slice(2); - return index && index > 0 ? new BN(accountHash, "hex").umod(ecCurve.curve.n) : new BN(0); - } } export default ThresholdKey; From 0769f27d830319528c09c0065fc2e574b43e575b Mon Sep 17 00:00:00 2001 From: guru-web3 <105355858+guru-web3@users.noreply.github.com> Date: Wed, 21 Feb 2024 16:04:51 +0530 Subject: [PATCH 18/23] fix: cleanup --- packages/core/src/core.ts | 4 ++-- packages/core/src/metadata.ts | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index eb85b63e1..7d0ca27ad 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -486,8 +486,8 @@ class ThresholdKey implements ITKey { // we need to add the pub key nonce to the tssPub const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); const pubKeyPoint = ecCurve.keyFromPublic({ x: tssCommits[0].x.toString("hex"), y: tssCommits[0].y.toString("hex") }).getPublic(); - const dervicepubKeyPoint = pubKeyPoint.add(noncePub); - return new Point(dervicepubKeyPoint.getX().toString("hex"), dervicepubKeyPoint.getY().toString("hex")); + const devicePubKeyPoint = pubKeyPoint.add(noncePub); + return new Point(devicePubKeyPoint.getX().toString("hex"), devicePubKeyPoint.getY().toString("hex")); } return tssCommits[0]; } diff --git a/packages/core/src/metadata.ts b/packages/core/src/metadata.ts index c2222e239..2c1cde092 100644 --- a/packages/core/src/metadata.ts +++ b/packages/core/src/metadata.ts @@ -186,7 +186,6 @@ class Metadata implements IMetadata { tssNonce?: number; tssPolyCommits?: Point[]; factorPubs?: Point[]; - accountIndex?: number; factorEncs?: { [factorPubID: string]: FactorEnc; }; From 99dbec34327d35e3c7a0ec8016c48b6d2a09a895 Mon Sep 17 00:00:00 2001 From: ieow Date: Fri, 23 Feb 2024 11:48:56 +0800 Subject: [PATCH 19/23] fix: add check before slice --- packages/core/src/core.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 7d0ca27ad..06695368e 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -1675,13 +1675,13 @@ class ThresholdKey implements ITKey { // read errors for what each means if (latestMetadata.nonce > this.lastFetchedCloudMetadata.nonce) { - throw CoreError.acquireLockFailed(`unable to acquire write access for metadata due to + throw CoreError.acquireLockFailed(`unable to acquire write access for metadata due to lastFetchedCloudMetadata (${this.lastFetchedCloudMetadata.nonce}) being lower than last written metadata nonce (${latestMetadata.nonce}). perhaps update metadata SDK (create new tKey and init)`); } else if (latestMetadata.nonce < this.lastFetchedCloudMetadata.nonce) { - throw CoreError.acquireLockFailed(`unable to acquire write access for metadata due to + throw CoreError.acquireLockFailed(`unable to acquire write access for metadata due to lastFetchedCloudMetadata (${this.lastFetchedCloudMetadata.nonce}) - being higher than last written metadata nonce (${latestMetadata.nonce}). this should never happen as it + being higher than last written metadata nonce (${latestMetadata.nonce}). this should never happen as it should only ever be updated by getting metadata)`); } @@ -1975,7 +1975,8 @@ class ThresholdKey implements ITKey { if (!this._accountSalt) { throw CoreError.accountSaltUndefined(); } - const accountHash = keccak256(Buffer.from(`${index}${this._accountSalt}`)).slice(2); + let accountHash = keccak256(Buffer.from(`${index}${this._accountSalt}`)); + if (accountHash.length === 66) accountHash = accountHash.slice(2); return index && index > 0 ? new BN(accountHash, "hex").umod(ecCurve.curve.n) : new BN(0); } From 11af4f2d73a77151e4a219780dfb6ce274a37fde Mon Sep 17 00:00:00 2001 From: ieow Date: Fri, 23 Feb 2024 15:27:46 +0800 Subject: [PATCH 20/23] fix: support backward compatible --- packages/core/src/core.ts | 17 +- .../default/test/RefreshAndAccountIndex.js | 195 ++++++++++++++++++ packages/default/test/helpers.js | 14 +- packages/default/test/shared.js | 179 ++-------------- 4 files changed, 235 insertions(+), 170 deletions(-) create mode 100644 packages/default/test/RefreshAndAccountIndex.js diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 06695368e..5bfa99b12 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -305,7 +305,7 @@ class ThresholdKey implements ITKey { if (useTSS) { const { factorEncs, factorPubs, tssPolyCommits } = await this._initializeNewTSSKey(this.tssTag, deviceTSSShare, factorPub, deviceTSSIndex); const accountSalt = generateSalt(); - this._setTKeyStoreItem(TSS_MODULE, { + await this._setTKeyStoreItem(TSS_MODULE, { id: "accountSalt", value: accountSalt, }); @@ -621,9 +621,20 @@ class ThresholdKey implements ITKey { ); } + // only valid for use Tss // assign account salt from tKey store if it exists const accountSalt = await this.getTKeyStoreItem(TSS_MODULE, "accountSalt"); - if (accountSalt && accountSalt?.value) this._accountSalt = accountSalt.value; + if (accountSalt && accountSalt?.value) { + this._accountSalt = accountSalt.value; + } else { + const newSalt = generateSalt(); + await this._setTKeyStoreItem(TSS_MODULE, { + id: "accountSalt", + value: newSalt, + }); + this._accountSalt = newSalt; + await this._syncShareMetadata(); + } return { privKey, ...returnObject }; } @@ -916,7 +927,7 @@ class ThresholdKey implements ITKey { factorPubs, factorEncs, }); - this._setTKeyStoreItem(TSS_MODULE, { + await this._setTKeyStoreItem(TSS_MODULE, { id: "accountSalt", value: accountSalt, }); diff --git a/packages/default/test/RefreshAndAccountIndex.js b/packages/default/test/RefreshAndAccountIndex.js new file mode 100644 index 000000000..361db3f81 --- /dev/null +++ b/packages/default/test/RefreshAndAccountIndex.js @@ -0,0 +1,195 @@ +import { ecCurve, getPubKeyPoint } from "@tkey-mpc/common-types"; +import { generatePrivate } from "@toruslabs/eccrypto"; +import { fail, notEqual, rejects, strictEqual } from "assert"; +import BN from "bn.js"; + +import ThresholdKey from "../src/index"; +import { assignTssDkgKeys, computeIndexedPrivateKey, fetchPostboxKeyAndSigs, getMetadataUrl, initStorageLayer } from "./helpers"; + +const TSS_MODULE = "tssModule"; +const metadataURL = getMetadataUrl(); + +// eslint-disable-next-line mocha/no-exports +export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwardCompatible) => { + const mode = manualSync; + + describe.only("RefreshAndAccountIndex", function () { + it("#should be able to refresh tss shares", async function () { + const sp = customSP; + if (!sp.useTSS) this.skip(); + + const deviceTSSShare = new BN(generatePrivate()); + const deviceTSSIndex = 2; + + sp.verifierName = "torus-test-health"; + sp.verifierId = "test19@example.com"; + const testId = sp.getVerifierNameVerifierId(); + const { signatures, postboxkey } = await fetchPostboxKeyAndSigs({ + serviceProvider: sp, + verifierName: sp.verifierName, + verifierId: sp.verifierId, + }); + sp.postboxKey = postboxkey; + const { serverDKGPrivKeys } = await assignTssDkgKeys({ + serviceProvider: sp, + verifierName: sp.verifierName, + verifierId: sp.verifierId, + maxTSSNonceToSimulate: 3, + }); + + const storageLayer = initStorageLayer({ hostUrl: metadataURL }); + const tb0 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); + + // accountSalt is absent, required for nonce generation + // can be only initialize with tkey.initialize(); + rejects(async () => { + tb0.computeAccountNonce(1); + }); + // factor key needs to passed from outside of tKey + const factorKey = new BN(generatePrivate()); + const factorPub = getPubKeyPoint(factorKey); + + await tb0.initialize({ useTSS: true, factorPub, deviceTSSShare, deviceTSSIndex }); + await tb0.reconstructKey(); + + // Test for backward compatibility ( accountSalt is absent for old account ) + if (accountIndexBackwardCompatible) { + await tb0._deleteTKeyStoreItem(TSS_MODULE, "accountSalt"); + } + + const newShare = await tb0.generateNewShare(); + await tb0.syncLocalMetadataTransitions(); + + const tb1 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); + await tb1.initialize({ useTSS: true, factorPub, deviceTSSShare, deviceTSSIndex }); + + // const newShare = await tb1.generateNewShare(); + await tb1.inputShareStoreSafe(newShare.newShareStores[newShare.newShareIndex.toString("hex")]); + const reconstructedKey = await tb1.reconstructKey(); + + if (tb1.privKey.cmp(reconstructedKey.privKey) !== 0) { + fail("key should be able to be reconstructed"); + } + + const tssPrivKey1 = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[0], 1); + const tssPubKeyIndex0 = ecCurve.keyFromPrivate(tssPrivKey1).getPublic(); + + const pubKey1 = tb1.getTSSPub(1); + strictEqual(tssPubKeyIndex0.x.toString(16, 64), pubKey1.x.toString(16, 64)); + strictEqual(tssPubKeyIndex0.y.toString(16, 64), pubKey1.y.toString(16, 64)); + + const factorKey1 = new BN(generatePrivate()); + const factorPub1 = getPubKeyPoint(factorKey1); + + const factorPubs1 = [factorPub, factorPub1]; + const { serverEndpoints, serverPubKeys } = await sp.getRSSNodeDetails(); + const { tssShare: retrievedTSSShare1, tssIndex: retrievedTSSIdx1 } = await tb1.getTSSShare(factorKey); + await tb1._refreshTSSShares(true, retrievedTSSShare1, retrievedTSSIdx1, factorPubs1, [2, 3], testId, { + serverThreshold: 3, + selectedServers: [1, 2, 3], + serverEndpoints, + serverPubKeys, + authSignatures: signatures, + }); + await tb1.syncLocalMetadataTransitions(); + + const tssPrivKeyIndex1 = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 1); + const tssPrivKeyIndex2 = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 2); + + const tssPubKeyIndex1 = ecCurve.keyFromPrivate(tssPrivKeyIndex1).getPublic(); + + const pubKeyIndex1 = tb1.getTSSPub(1); + strictEqual(tssPubKeyIndex1.x.toString(16, 64), pubKeyIndex1.x.toString(16, 64)); + strictEqual(tssPubKeyIndex1.y.toString(16, 64), pubKeyIndex1.y.toString(16, 64)); + + const tb2 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); + await tb2.initialize({ useTSS: true, factorPub }); + await tb2.inputShareStoreSafe(newShare.newShareStores[newShare.newShareIndex.toString("hex")]); + await tb2.reconstructKey(); + + const tssPrivKeytb2Index2 = await computeIndexedPrivateKey(tb2, factorKey, serverDKGPrivKeys[1], 2); + strictEqual(tssPrivKeyIndex2.toString("hex"), tssPrivKeytb2Index2.toString("hex")); + + const tssPubKeytb2Index2 = getPubKeyPoint(tssPrivKeytb2Index2); + const pubKey2Index2 = tb2.getTSSPub(2); + + strictEqual(tssPubKeytb2Index2.x.toString(16, 64), pubKey2Index2.x.toString(16, 64)); + strictEqual(tssPubKeytb2Index2.y.toString(16, 64), pubKey2Index2.y.toString(16, 64)); + + // // test tss refresh + const factorKey2 = new BN(generatePrivate()); + const factorPub2 = getPubKeyPoint(factorKey2); + + const factorPubs2 = [factorPub, factorPub2]; + const { tssShare: retrievedTSS3, tssIndex: retrievedTSSIndex3 } = await tb2.getTSSShare(factorKey); + await tb2._refreshTSSShares(true, retrievedTSS3, retrievedTSSIndex3, factorPubs2, [2, 3], testId, { + serverThreshold: 3, + selectedServers: [1, 2, 3], + serverEndpoints, + serverPubKeys, + authSignatures: signatures, + }); + + // test case to ensure nonce mechanism + { + // make sure derived pub key is different from the index 0 key + notEqual(tssPubKeyIndex0.x.toString(16, 64), tssPubKeytb2Index2.x.toString(16, 64)); + notEqual(tssPubKeyIndex0.y.toString(16, 64), tssPubKeytb2Index2.y.toString(16, 64)); + + const { tssShare: retrievedTSS } = await tb2.getTSSShare(factorKey); + const tssSharePub = ecCurve.keyFromPrivate(retrievedTSS.toString("hex")).getPublic(); + const { tssShare: retrievedTSSIndex1 } = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); + const tssSharePubIndex1 = ecCurve.keyFromPrivate(retrievedTSSIndex1.toString("hex")).getPublic(); + + const nonce = tb2.computeAccountNonce(1); + const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); + const tssShareDerived = tssSharePub.add(noncePub); + + strictEqual(tssShareDerived.getX().toString("hex"), tssSharePubIndex1.getX().toString("hex")); + strictEqual(tssShareDerived.getY().toString("hex"), tssSharePubIndex1.getY().toString("hex")); + + const { tssShare: retrievedTSS31 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); + const tssSharePub3 = ecCurve.keyFromPrivate(retrievedTSS31.toString("hex")).getPublic(); + const nonce2 = tb2.computeAccountNonce(2); + const noncePub2 = ecCurve.keyFromPrivate(nonce2.toString("hex")).getPublic(); + const tssShareDerived2 = tssSharePub.add(noncePub2); + strictEqual(tssShareDerived2.getX().toString("hex"), tssSharePub3.getX().toString("hex")); + strictEqual(tssShareDerived2.getY().toString("hex"), tssSharePub3.getY().toString("hex")); + } + + // check for account 1 and 2 after refresh share ( tb1 only refresh once ) + { + const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); + const computedKey = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 1); + strictEqual(tssPrivKey1.toString(16, 64), computedKey.toString(16, 64)); + // eslint-disable-next-line no-console + console.log("newTSS", newTSS.toString("hex"), tssIndex); + } + + { + const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 2 }); + const computedKey = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 2); + strictEqual(tssPrivKeyIndex2.toString(16, 64), computedKey.toString(16, 64)); + // eslint-disable-next-line no-console + console.log("newTSS", newTSS.toString("hex"), tssIndex); + } + + // check for account 1 and 2 after refresh share ( tb2 only refresh twice ) + { + const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 1 }); + const computedKey = await computeIndexedPrivateKey(tb2, factorKey2, serverDKGPrivKeys[2], 1); + strictEqual(tssPrivKey1.toString(16, 64), computedKey.toString(16, 64)); + // eslint-disable-next-line no-console + console.log("newTSS2", newTSS2.toString("hex"), tssIndex); + } + + { + const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 2 }); + const computedKey = await computeIndexedPrivateKey(tb2, factorKey2, serverDKGPrivKeys[2], 2); + strictEqual(tssPrivKeytb2Index2.toString(16, 64), computedKey.toString(16, 64)); + // eslint-disable-next-line no-console + console.log("newTSS2", newTSS2.toString("hex"), tssIndex); + } + }); + }); +}; diff --git a/packages/default/test/helpers.js b/packages/default/test/helpers.js index bba6014f9..dff60b4e9 100644 --- a/packages/default/test/helpers.js +++ b/packages/default/test/helpers.js @@ -1,9 +1,8 @@ -import { ecCurve, getPubKeyPoint, Point } from "@tkey-mpc/common-types"; +import { ecCurve, generatePrivate, getPubKeyPoint, Point } from "@tkey-mpc/common-types"; import ServiceProviderBase from "@tkey-mpc/service-provider-base"; import ServiceProviderTorus from "@tkey-mpc/service-provider-torus"; import TorusStorageLayer, { MockStorageLayer } from "@tkey-mpc/storage-layer-torus"; -import { generatePrivate } from "@toruslabs/eccrypto"; -import { generatePolynomial, getShare, hexPoint, MockServer, postEndpoint } from "@toruslabs/rss-client"; +import { generatePolynomial, getLagrangeCoeffs, getShare, hexPoint, MockServer, postEndpoint } from "@toruslabs/rss-client"; // eslint-disable-next-line import/no-extraneous-dependencies import Torus from "@toruslabs/torus.js"; import BN from "bn.js"; @@ -197,3 +196,12 @@ export async function assignTssDkgKeys(opts) { // serverDKGPubKeys, }; } + +export async function computeIndexedPrivateKey(tkey, factorKey, serverDKGPrivKeys, accountIndex) { + const { tssShare: retrievedTSS1, tssIndex: retrievedTSSIndex1 } = await tkey.getTSSShare(factorKey, { accountIndex }); + const tssPrivKey1 = getLagrangeCoeffs([1, retrievedTSSIndex1], 1) + .mul(serverDKGPrivKeys.add(tkey.computeAccountNonce(accountIndex))) + .add(getLagrangeCoeffs([1, retrievedTSSIndex1], retrievedTSSIndex1).mul(retrievedTSS1)) + .umod(ecCurve.n); + return tssPrivKey1; +} diff --git a/packages/default/test/shared.js b/packages/default/test/shared.js index ec2d28c15..25022b67a 100644 --- a/packages/default/test/shared.js +++ b/packages/default/test/shared.js @@ -22,7 +22,17 @@ import stringify from "json-stable-stringify"; import { createSandbox } from "sinon"; import ThresholdKey from "../src/index"; -import { assignTssDkgKeys, fetchPostboxKeyAndSigs, getMetadataUrl, getServiceProvider, initStorageLayer, isMocked, setupTSSMocks } from "./helpers"; +import { + assignTssDkgKeys, + computeIndexedPrivateKey, + fetchPostboxKeyAndSigs, + getMetadataUrl, + getServiceProvider, + initStorageLayer, + isMocked, + setupTSSMocks, +} from "./helpers"; +import { refreshAndAccountIndex } from "./RefreshAndAccountIndex"; const rejects = async (fn, error, msg) => { let f = () => {}; @@ -67,172 +77,13 @@ function compareReconstructedKeys(a, b, message) { export const sharedTestCases = (mode, torusSP, storageLayer) => { const customSP = torusSP; const customSL = storageLayer; - describe("TSS tests", function () { - it("#should be able to refresh tss shares", async function () { - const sp = customSP; - if (!sp.useTSS) this.skip(); - - const deviceTSSShare = new BN(generatePrivate()); - const deviceTSSIndex = 2; - - sp.verifierName = "torus-test-health"; - sp.verifierId = "test19@example.com"; - const testId = sp.getVerifierNameVerifierId(); - const { signatures, postboxkey } = await fetchPostboxKeyAndSigs({ - serviceProvider: sp, - verifierName: sp.verifierName, - verifierId: sp.verifierId, - }); - sp.postboxKey = postboxkey; - const { serverDKGPrivKeys } = await assignTssDkgKeys({ - serviceProvider: sp, - verifierName: sp.verifierName, - verifierId: sp.verifierId, - maxTSSNonceToSimulate: 2, - }); - const storageLayer = initStorageLayer({ hostUrl: metadataURL }); - const tb1 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); - - // accountSalt is absent, required for nonce generation - // can be only initialize with tkey.initialize(); - rejects(async () => { - tb1.computeAccountNonce(1); - }); - // factor key needs to passed from outside of tKey - const factorKey = new BN(generatePrivate()); - const factorPub = getPubKeyPoint(factorKey); - - await tb1.initialize({ useTSS: true, factorPub, deviceTSSShare, deviceTSSIndex }); - const newShare = await tb1.generateNewShare(); - const reconstructedKey = await tb1.reconstructKey(); - await tb1.syncLocalMetadataTransitions(); - if (tb1.privKey.cmp(reconstructedKey.privKey) !== 0) { - fail("key should be able to be reconstructed"); - } - const { tssShare: retrievedTSS1, tssIndex: retrievedTSSIndex1 } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); - const tssPrivKey1 = getLagrangeCoeffs([1, retrievedTSSIndex1], 1) - .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(1))) - .add(getLagrangeCoeffs([1, retrievedTSSIndex1], retrievedTSSIndex1).mul(retrievedTSS1)) - .umod(ecCurve.n); - const tssPubKey1 = ecCurve.keyFromPrivate(tssPrivKey1).getPublic(); - - const pubKey1 = tb1.getTSSPub(1); - strictEqual(tssPubKey1.x.toString(16, 64), pubKey1.x.toString(16, 64)); - strictEqual(tssPubKey1.y.toString(16, 64), pubKey1.y.toString(16, 64)); - - const factorKey1 = new BN(generatePrivate()); - const factorPub1 = getPubKeyPoint(factorKey1); - - const factorPubs1 = [factorPub, factorPub1]; - const { serverEndpoints, serverPubKeys } = await sp.getRSSNodeDetails(); - const { tssShare: retrievedTSSShare1, tssIndex: retrievedTSSIdx1 } = await tb1.getTSSShare(factorKey); - await tb1._refreshTSSShares(true, retrievedTSSShare1, retrievedTSSIdx1, factorPubs1, [2, 3], testId, { - serverThreshold: 3, - selectedServers: [1, 2, 3], - serverEndpoints, - serverPubKeys, - authSignatures: signatures, - }); - - const tb2 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); - await tb2.initialize({ useTSS: true, factorPub }); - await tb2.inputShareStoreSafe(newShare.newShareStores[newShare.newShareIndex.toString("hex")]); - await tb2.reconstructKey(); - - const { tssShare: retrievedTSS2, tssIndex: retrievedTSSIndex2 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); - const tssPrivKey2 = getLagrangeCoeffs([1, retrievedTSSIndex2], 1) - .mul(serverDKGPrivKeys[0].add(tb1.computeAccountNonce(2))) - .add(getLagrangeCoeffs([1, retrievedTSSIndex2], retrievedTSSIndex2).mul(retrievedTSS2)) - .umod(ecCurve.n); - const tssPubKey2 = getPubKeyPoint(tssPrivKey2); - const pubKey2 = tb1.getTSSPub(2); + // backward compatibility test + refreshAndAccountIndex(customSP, mode, true); - strictEqual(tssPubKey2.x.toString(16, 64), pubKey2.x.toString(16, 64)); - strictEqual(tssPubKey2.y.toString(16, 64), pubKey2.y.toString(16, 64)); - - // // test tss refresh - const factorKey2 = new BN(generatePrivate()); - const factorPub2 = getPubKeyPoint(factorKey2); + refreshAndAccountIndex(customSP, mode, false); - const factorPubs2 = [factorPub, factorPub2]; - const { tssShare: retrievedTSS3, tssIndex: retrievedTSSIndex3 } = await tb2.getTSSShare(factorKey); - await tb2._refreshTSSShares(true, retrievedTSS3, retrievedTSSIndex3, factorPubs2, [2, 3], testId, { - serverThreshold: 3, - selectedServers: [1, 2, 3], - serverEndpoints, - serverPubKeys, - authSignatures: signatures, - }); - - // test case to ensure nonce mechanism - { - notEqual(tssPubKey1.x.toString(16, 64), tssPubKey2.x.toString(16, 64)); - notEqual(tssPubKey1.y.toString(16, 64), tssPubKey2.y.toString(16, 64)); - - const { tssShare: retrievedTSS } = await tb2.getTSSShare(factorKey); - const tssSharePub = ecCurve.keyFromPrivate(retrievedTSS.toString("hex")).getPublic(); - const { tssShare: retrievedTSS2 } = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); - const tssSharePub2 = ecCurve.keyFromPrivate(retrievedTSS2.toString("hex")).getPublic(); - const nonce = tb1.computeAccountNonce(1); - const noncePub = ecCurve.keyFromPrivate(nonce.toString("hex")).getPublic(); - const tssShareDerived = tssSharePub.add(noncePub); - strictEqual(tssShareDerived.getX().toString("hex"), tssSharePub2.getX().toString("hex")); - strictEqual(tssShareDerived.getY().toString("hex"), tssSharePub2.getY().toString("hex")); - - const { tssShare: retrievedTSS3 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); - const tssSharePub3 = ecCurve.keyFromPrivate(retrievedTSS3.toString("hex")).getPublic(); - const nonce2 = tb1.computeAccountNonce(2); - const noncePub2 = ecCurve.keyFromPrivate(nonce2.toString("hex")).getPublic(); - const tssShareDerived2 = tssSharePub.add(noncePub2); - strictEqual(tssShareDerived2.getX().toString("hex"), tssSharePub3.getX().toString("hex")); - strictEqual(tssShareDerived2.getY().toString("hex"), tssSharePub3.getY().toString("hex")); - } - - { - const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); - const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) - .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) - .umod(ecCurve.n); - strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS", newTSS.toString("hex"), tssIndex); - } - - { - const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 1 }); - const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(1))) - .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) - .umod(ecCurve.n); - strictEqual(tssPrivKey1.toString(16, 64), newTSSPrivKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS2", newTSS2.toString("hex"), tssIndex); - } - - { - const { tssShare: newTSS, tssIndex } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); - const newTSSPrivKey = getLagrangeCoeffs([1, 2], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb2.computeAccountNonce(2))) - .add(getLagrangeCoeffs([1, 2], 2).mul(newTSS)) - .umod(ecCurve.n); - strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS", newTSS.toString("hex"), tssIndex); - } - - { - const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 2 }); - const newTSSPrivKey = getLagrangeCoeffs([1, 3], 1) - .mul(new BN(serverDKGPrivKeys[1], "hex").add(tb1.computeAccountNonce(2))) - .add(getLagrangeCoeffs([1, 3], 3).mul(newTSS2)) - .umod(ecCurve.n); - strictEqual(tssPrivKey2.toString(16, 64), newTSSPrivKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS2", newTSS2.toString("hex"), tssIndex); - } - }); + describe("TSS tests", function () { it("#should be able to reconstruct tssShare from factor key (tss2) when initializing a key with useTSS true", async function () { const sp = customSP; if (!sp.useTSS) this.skip(); From 0d78a92b8126179e25370dc403fad26a2811b9be Mon Sep 17 00:00:00 2001 From: ieow Date: Fri, 23 Feb 2024 15:34:20 +0800 Subject: [PATCH 21/23] fix: generatePrivate --- packages/default/test/RefreshAndAccountIndex.js | 3 ++- packages/default/test/helpers.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/default/test/RefreshAndAccountIndex.js b/packages/default/test/RefreshAndAccountIndex.js index 361db3f81..f732098df 100644 --- a/packages/default/test/RefreshAndAccountIndex.js +++ b/packages/default/test/RefreshAndAccountIndex.js @@ -1,4 +1,5 @@ import { ecCurve, getPubKeyPoint } from "@tkey-mpc/common-types"; +// eslint-disable-next-line import/no-extraneous-dependencies import { generatePrivate } from "@toruslabs/eccrypto"; import { fail, notEqual, rejects, strictEqual } from "assert"; import BN from "bn.js"; @@ -13,7 +14,7 @@ const metadataURL = getMetadataUrl(); export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwardCompatible) => { const mode = manualSync; - describe.only("RefreshAndAccountIndex", function () { + describe("RefreshAndAccountIndex", function () { it("#should be able to refresh tss shares", async function () { const sp = customSP; if (!sp.useTSS) this.skip(); diff --git a/packages/default/test/helpers.js b/packages/default/test/helpers.js index dff60b4e9..0f1cecf2a 100644 --- a/packages/default/test/helpers.js +++ b/packages/default/test/helpers.js @@ -1,7 +1,8 @@ -import { ecCurve, generatePrivate, getPubKeyPoint, Point } from "@tkey-mpc/common-types"; +import { ecCurve, getPubKeyPoint, Point } from "@tkey-mpc/common-types"; import ServiceProviderBase from "@tkey-mpc/service-provider-base"; import ServiceProviderTorus from "@tkey-mpc/service-provider-torus"; import TorusStorageLayer, { MockStorageLayer } from "@tkey-mpc/storage-layer-torus"; +import { generatePrivate } from "@toruslabs/eccrypto"; import { generatePolynomial, getLagrangeCoeffs, getShare, hexPoint, MockServer, postEndpoint } from "@toruslabs/rss-client"; // eslint-disable-next-line import/no-extraneous-dependencies import Torus from "@toruslabs/torus.js"; From ee82873f3b549cbd61bc379ec3f709652f78a502 Mon Sep 17 00:00:00 2001 From: ieow Date: Fri, 23 Feb 2024 16:11:17 +0800 Subject: [PATCH 22/23] fix: remove syncMetadata --- packages/core/src/core.ts | 24 +++++++++---------- .../default/test/RefreshAndAccountIndex.js | 16 ++----------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 5bfa99b12..c68296848 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -623,17 +623,18 @@ class ThresholdKey implements ITKey { // only valid for use Tss // assign account salt from tKey store if it exists - const accountSalt = await this.getTKeyStoreItem(TSS_MODULE, "accountSalt"); - if (accountSalt && accountSalt?.value) { - this._accountSalt = accountSalt.value; - } else { - const newSalt = generateSalt(); - await this._setTKeyStoreItem(TSS_MODULE, { - id: "accountSalt", - value: newSalt, - }); - this._accountSalt = newSalt; - await this._syncShareMetadata(); + if (Object.keys(this.metadata.tssPolyCommits).length > 0) { + const accountSalt = await this.getTKeyStoreItem(TSS_MODULE, "accountSalt"); + if (accountSalt && accountSalt?.value) { + this._accountSalt = accountSalt.value; + } else { + const newSalt = generateSalt(); + await this._setTKeyStoreItem(TSS_MODULE, { + id: "accountSalt", + value: newSalt, + }); + this._accountSalt = newSalt; + } } return { privKey, ...returnObject }; @@ -931,7 +932,6 @@ class ThresholdKey implements ITKey { id: "accountSalt", value: accountSalt, }); - await this._syncShareMetadata(); } catch (error) { this.tssTag = oldTag; throw error; diff --git a/packages/default/test/RefreshAndAccountIndex.js b/packages/default/test/RefreshAndAccountIndex.js index f732098df..f9b652f0b 100644 --- a/packages/default/test/RefreshAndAccountIndex.js +++ b/packages/default/test/RefreshAndAccountIndex.js @@ -13,8 +13,8 @@ const metadataURL = getMetadataUrl(); // eslint-disable-next-line mocha/no-exports export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwardCompatible) => { const mode = manualSync; - - describe("RefreshAndAccountIndex", function () { + const { useTSS } = customSP; + describe(`RefreshAndAccountIndex : useTss ${useTSS}, manualSync ${manualSync}, bcAccountIndex ${accountIndexBackwardCompatible}`, function () { it("#should be able to refresh tss shares", async function () { const sp = customSP; if (!sp.useTSS) this.skip(); @@ -160,36 +160,24 @@ export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwar // check for account 1 and 2 after refresh share ( tb1 only refresh once ) { - const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); const computedKey = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 1); strictEqual(tssPrivKey1.toString(16, 64), computedKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS", newTSS.toString("hex"), tssIndex); } { - const { tssShare: newTSS, tssIndex } = await tb1.getTSSShare(factorKey, { accountIndex: 2 }); const computedKey = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 2); strictEqual(tssPrivKeyIndex2.toString(16, 64), computedKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS", newTSS.toString("hex"), tssIndex); } // check for account 1 and 2 after refresh share ( tb2 only refresh twice ) { - const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 1 }); const computedKey = await computeIndexedPrivateKey(tb2, factorKey2, serverDKGPrivKeys[2], 1); strictEqual(tssPrivKey1.toString(16, 64), computedKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS2", newTSS2.toString("hex"), tssIndex); } { - const { tssShare: newTSS2, tssIndex } = await tb2.getTSSShare(factorKey2, { accountIndex: 2 }); const computedKey = await computeIndexedPrivateKey(tb2, factorKey2, serverDKGPrivKeys[2], 2); strictEqual(tssPrivKeytb2Index2.toString(16, 64), computedKey.toString(16, 64)); - // eslint-disable-next-line no-console - console.log("newTSS2", newTSS2.toString("hex"), tssIndex); } }); }); From 8df32af61a96b9e9bddd62e19f6a625c6da7da5f Mon Sep 17 00:00:00 2001 From: ieow Date: Fri, 23 Feb 2024 16:26:29 +0800 Subject: [PATCH 23/23] fix: remove outdated type --- package-lock.json | 34 ++++++-------------- packages/common-types/package.json | 1 - packages/core/package.json | 1 - packages/private-keys/package.json | 1 - packages/security-questions/package.json | 1 - packages/seed-phrase/package.json | 1 - packages/service-provider-base/package.json | 1 - packages/service-provider-torus/package.json | 1 - packages/share-transfer/package.json | 1 - packages/storage-layer-torus/package.json | 1 - packages/web-storage/package.json | 5 +-- 11 files changed, 10 insertions(+), 38 deletions(-) diff --git a/package-lock.json b/package-lock.json index 391074081..d5f9f5cd0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4827,9 +4827,9 @@ "dev": true }, "node_modules/@types/bn.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.2.tgz", - "integrity": "sha512-dkpZu0szUtn9UXTmw+e0AJFd4D2XAxDnsCLdc05SfqpqzPEBft8eQr8uaFitfo/dUUOZERaLec2hHMG87A4Dxg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", "dependencies": { "@types/node": "*" } @@ -24264,7 +24264,6 @@ "ts-custom-error": "^3.3.1" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15" }, "engines": { @@ -24277,7 +24276,7 @@ }, "packages/core": { "name": "@tkey-mpc/core", - "version": "9.0.3", + "version": "9.0.2", "license": "MIT", "dependencies": { "@tkey-mpc/common-types": "^9.0.2", @@ -24290,7 +24289,6 @@ "json-stable-stringify": "^1.0.2" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15", "@types/json-stable-stringify": "^1.0.34" }, @@ -24345,9 +24343,7 @@ "bn.js": "^5.2.1", "randombytes": "^2.1.0" }, - "devDependencies": { - "@types/bn.js": "^5.1.2" - }, + "devDependencies": {}, "engines": { "node": ">=18.x", "npm": ">=9.x" @@ -24365,9 +24361,7 @@ "bn.js": "^5.2.1", "ethereum-cryptography": "^2.1.2" }, - "devDependencies": { - "@types/bn.js": "^5.1.2" - }, + "devDependencies": {}, "engines": { "node": ">=18.x", "npm": ">=9.x" @@ -24386,9 +24380,7 @@ "bn.js": "^5.2.1", "ethers": "^6.7.1" }, - "devDependencies": { - "@types/bn.js": "^5.1.2" - }, + "devDependencies": {}, "engines": { "node": ">=18.x", "npm": ">=9.x" @@ -24407,7 +24399,6 @@ "elliptic": "^6.5.4" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15" }, "engines": { @@ -24431,7 +24422,6 @@ "elliptic": "^6.5.4" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15" }, "engines": { @@ -24470,9 +24460,7 @@ "@toruslabs/http-helpers": "^5.0.0", "bn.js": "^5.2.1" }, - "devDependencies": { - "@types/bn.js": "^5.1.2" - }, + "devDependencies": {}, "engines": { "node": ">=18.x", "npm": ">=9.x" @@ -24494,7 +24482,6 @@ "json-stable-stringify": "^1.0.2" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/json-stable-stringify": "^1.0.34" }, "engines": { @@ -24511,16 +24498,13 @@ "license": "MIT", "dependencies": { "@tkey-mpc/common-types": "^9.0.2", - "@types/bn.js": "^5.1.1", "bn.js": "^5.2.1" }, "devDependencies": { "@tkey-mpc/core": "^9.0.2", "@tkey-mpc/service-provider-base": "^9.0.2", "@tkey-mpc/storage-layer-torus": "^9.0.2", - "@types/bn.js": "^5.1.2", - "@types/filesystem": "^0.0.33", - "bn.js": "^5.2.1" + "@types/filesystem": "^0.0.33" }, "engines": { "node": ">=18.x", diff --git a/packages/common-types/package.json b/packages/common-types/package.json index 7337d3bcf..f307b4932 100644 --- a/packages/common-types/package.json +++ b/packages/common-types/package.json @@ -53,7 +53,6 @@ "ts-custom-error": "^3.3.1" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15" }, "bugs": { diff --git a/packages/core/package.json b/packages/core/package.json index 05f692cd4..65aa88aab 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -44,7 +44,6 @@ "json-stable-stringify": "^1.0.2" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15", "@types/json-stable-stringify": "^1.0.34" }, diff --git a/packages/private-keys/package.json b/packages/private-keys/package.json index 4dba72b0b..1064bf03a 100644 --- a/packages/private-keys/package.json +++ b/packages/private-keys/package.json @@ -38,7 +38,6 @@ "@babel/runtime": "7.x" }, "devDependencies": { - "@types/bn.js": "^5.1.2" }, "dependencies": { "@tkey-mpc/common-types": "^9.0.2", diff --git a/packages/security-questions/package.json b/packages/security-questions/package.json index 64aea1bfc..3a0756168 100644 --- a/packages/security-questions/package.json +++ b/packages/security-questions/package.json @@ -46,7 +46,6 @@ "ethereum-cryptography": "^2.1.2" }, "devDependencies": { - "@types/bn.js": "^5.1.2" }, "lint-staged": { "!(*d).ts": [ diff --git a/packages/seed-phrase/package.json b/packages/seed-phrase/package.json index 0a18b34de..ec53b0612 100644 --- a/packages/seed-phrase/package.json +++ b/packages/seed-phrase/package.json @@ -47,7 +47,6 @@ "ethers": "^6.7.1" }, "devDependencies": { - "@types/bn.js": "^5.1.2" }, "lint-staged": { "!(*d).ts": [ diff --git a/packages/service-provider-base/package.json b/packages/service-provider-base/package.json index d91988d40..c4fe38d80 100644 --- a/packages/service-provider-base/package.json +++ b/packages/service-provider-base/package.json @@ -48,7 +48,6 @@ "elliptic": "^6.5.4" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15" }, "bugs": { diff --git a/packages/service-provider-torus/package.json b/packages/service-provider-torus/package.json index 455a99ddc..ceac3b946 100644 --- a/packages/service-provider-torus/package.json +++ b/packages/service-provider-torus/package.json @@ -46,7 +46,6 @@ "elliptic": "^6.5.4" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/elliptic": "^6.4.15" }, "bugs": { diff --git a/packages/share-transfer/package.json b/packages/share-transfer/package.json index 738910e80..bac94b293 100644 --- a/packages/share-transfer/package.json +++ b/packages/share-transfer/package.json @@ -44,7 +44,6 @@ "bn.js": "^5.2.1" }, "devDependencies": { - "@types/bn.js": "^5.1.2" }, "bugs": { "url": "https://github.com/tkey/tkey/issues" diff --git a/packages/storage-layer-torus/package.json b/packages/storage-layer-torus/package.json index df45fc04a..d275c1d3b 100644 --- a/packages/storage-layer-torus/package.json +++ b/packages/storage-layer-torus/package.json @@ -46,7 +46,6 @@ "json-stable-stringify": "^1.0.2" }, "devDependencies": { - "@types/bn.js": "^5.1.2", "@types/json-stable-stringify": "^1.0.34" }, "bugs": { diff --git a/packages/web-storage/package.json b/packages/web-storage/package.json index 147817323..d9229d5d0 100644 --- a/packages/web-storage/package.json +++ b/packages/web-storage/package.json @@ -44,16 +44,13 @@ }, "dependencies": { "@tkey-mpc/common-types": "^9.0.2", - "@types/bn.js": "^5.1.1", "bn.js": "^5.2.1" }, "devDependencies": { "@tkey-mpc/core": "^9.0.2", "@tkey-mpc/service-provider-base": "^9.0.2", "@tkey-mpc/storage-layer-torus": "^9.0.2", - "@types/bn.js": "^5.1.2", - "@types/filesystem": "^0.0.33", - "bn.js": "^5.2.1" + "@types/filesystem": "^0.0.33" }, "bugs": { "url": "https://github.com/tkey/tkey/issues"