-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from tkey/fix/softnonce-tssShare-threshold
fix: make threshold in option optional
- Loading branch information
Showing
2 changed files
with
138 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,104 @@ | ||
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 assert, { 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(); | ||
|
||
const TSS_MODULE = "tssModule"; | ||
// eslint-disable-next-line mocha/no-exports | ||
export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwardCompatible) => { | ||
export const refreshAndAccountIndex = (customSP, manualSync, resetAccountSalt) => { | ||
const mode = manualSync; | ||
const { useTSS } = customSP; | ||
describe(`RefreshAndAccountIndex : useTss ${useTSS}, manualSync ${manualSync}, bcAccountIndex ${accountIndexBackwardCompatible}`, function () { | ||
describe(`RefreshAndAccountIndex : useTss ${useTSS}, manualSync ${manualSync}, bcAccountIndex ${resetAccountSalt}`, function () { | ||
it("#should be able to get same key each login using differnt accountIndex", 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 = "[email protected]"; | ||
const testId = sp.getVerifierNameVerifierId(); | ||
const { postboxkey } = await fetchPostboxKeyAndSigs({ | ||
serviceProvider: sp, | ||
verifierName: sp.verifierName, | ||
verifierId: sp.verifierId, | ||
}); | ||
sp.postboxKey = postboxkey; | ||
|
||
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 ) | ||
|
||
const tss0ShareIndex0 = await tb0.getTSSShare(factorKey); | ||
const tss0ShareIndex1 = await tb0.getTSSShare(factorKey, { accountIndex: 1 }); | ||
const tss0ShareIndex2 = await tb0.getTSSShare(factorKey, { accountIndex: 2 }); | ||
const tss0ShareIndex99 = await tb0.getTSSShare(factorKey, { accountIndex: 99 }); | ||
if (resetAccountSalt) { | ||
// tb0.metadata.encryptedSalt = {}; | ||
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 }); | ||
await tb1.inputShareStoreSafe(newShare.newShareStores[newShare.newShareIndex.toString("hex")]); | ||
await tb1.reconstructKey(); | ||
|
||
const tss1ShareIndex0 = await tb1.getTSSShare(factorKey); | ||
const tss1ShareIndex1 = await tb1.getTSSShare(factorKey, { accountIndex: 1 }); | ||
const tss1ShareIndex2 = await tb1.getTSSShare(factorKey, { accountIndex: 2 }); | ||
const tss1ShareIndex99 = await tb1.getTSSShare(factorKey, { accountIndex: 99 }); | ||
|
||
const tb2 = new ThresholdKey({ serviceProvider: sp, storageLayer, manualSync: mode }); | ||
await tb2.initialize({ useTSS: true, factorPub, deviceTSSShare, deviceTSSIndex }); | ||
await tb2.inputShareStoreSafe(newShare.newShareStores[newShare.newShareIndex.toString("hex")]); | ||
await tb2.reconstructKey(); | ||
|
||
const tss2ShareIndex0 = await tb2.getTSSShare(factorKey); | ||
const tss2ShareIndex1 = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); | ||
const tss2ShareIndex2 = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); | ||
const tss2ShareIndex99 = await tb2.getTSSShare(factorKey, { accountIndex: 99 }); | ||
|
||
strictEqual(tss0ShareIndex0.tssShare.toString("hex"), tss1ShareIndex0.tssShare.toString("hex")); | ||
|
||
// expect different account address when accountSalt is reseted ( to support existing account that do not have this features) | ||
if (resetAccountSalt) { | ||
notEqual(tss0ShareIndex1.tssShare.toString("hex"), tss1ShareIndex1.tssShare.toString("hex")); | ||
notEqual(tss0ShareIndex2.tssShare.toString("hex"), tss1ShareIndex2.tssShare.toString("hex")); | ||
notEqual(tss0ShareIndex99.tssShare.toString("hex"), tss1ShareIndex99.tssShare.toString("hex")); | ||
} else { | ||
strictEqual(tss0ShareIndex1.tssShare.toString("hex"), tss1ShareIndex1.tssShare.toString("hex")); | ||
strictEqual(tss0ShareIndex2.tssShare.toString("hex"), tss1ShareIndex2.tssShare.toString("hex")); | ||
strictEqual(tss0ShareIndex99.tssShare.toString("hex"), tss1ShareIndex99.tssShare.toString("hex")); | ||
} | ||
|
||
// expect same account address after relogin | ||
strictEqual(tss1ShareIndex0.tssShare.toString("hex"), tss2ShareIndex0.tssShare.toString("hex")); | ||
strictEqual(tss1ShareIndex1.tssShare.toString("hex"), tss2ShareIndex1.tssShare.toString("hex")); | ||
strictEqual(tss1ShareIndex2.tssShare.toString("hex"), tss2ShareIndex2.tssShare.toString("hex")); | ||
strictEqual(tss1ShareIndex99.tssShare.toString("hex"), tss2ShareIndex99.tssShare.toString("hex")); | ||
}); | ||
|
||
it("#should be able to refresh tss shares", async function () { | ||
const sp = customSP; | ||
if (!sp.useTSS) this.skip(); | ||
|
@@ -52,10 +136,11 @@ export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwar | |
|
||
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"); | ||
|
||
if (resetAccountSalt) { | ||
// eslint-disable-next-line require-atomic-updates | ||
tb0.metadata.encryptedSalt = {}; | ||
} | ||
|
||
const newShare = await tb0.generateNewShare(); | ||
|
@@ -92,8 +177,9 @@ export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwar | |
serverPubKeys, | ||
authSignatures: signatures, | ||
}); | ||
await tb1.syncLocalMetadataTransitions(); | ||
|
||
if (manualSync) { | ||
await tb1.syncLocalMetadataTransitions(); | ||
} | ||
const tssPrivKeyIndex1 = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 1); | ||
const tssPrivKeyIndex2 = await computeIndexedPrivateKey(tb1, factorKey, serverDKGPrivKeys[1], 2); | ||
|
||
|
@@ -131,6 +217,22 @@ export const refreshAndAccountIndex = (customSP, manualSync, accountIndexBackwar | |
authSignatures: signatures, | ||
}); | ||
|
||
{ | ||
// ensure tssShare is the master share | ||
const { tssShare } = await tb2.getTSSShare(factorKey); | ||
const { tssShare: tssShareIndex1 } = await tb2.getTSSShare(factorKey, { accountIndex: 1 }); | ||
const { tssShare: tssShareIndex2 } = await tb2.getTSSShare(factorKey, { accountIndex: 2 }); | ||
const { tssShare: tssShareIndex0 } = await tb2.getTSSShare(factorKey, { accountIndex: 0 }); | ||
|
||
const nonce1 = tb2.computeAccountNonce(1); | ||
const nonce2 = tb2.computeAccountNonce(2); | ||
|
||
assert(tb2.computeAccountNonce(0).eq(new BN(0)), "nonce for account 0 should be 0"); | ||
assert(tssShare.eq(tssShareIndex0), "tssShareIndex0 should be equal to tssShare"); | ||
assert(tssShare.add(nonce1).umod(ecCurve.n).eq(tssShareIndex1), "tssShareIndex1 should be equal to tssShare + nonce1"); | ||
assert(tssShare.add(nonce2).umod(ecCurve.n).eq(tssShareIndex2), "tssShareIndex2 should be equal to tssShare + nonce2"); | ||
assert(!tssShareIndex1.add(nonce1).umod(ecCurve.n).eq(tssShareIndex2), "tssShareIndex2 should not be equal to tssShareIndex1 + nonce1"); | ||
} | ||
// test case to ensure nonce mechanism | ||
{ | ||
// make sure derived pub key is different from the index 0 key | ||
|