Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: soft nonce implementation #6

Merged
merged 23 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .github/workflows/backward.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ jobs:
steps:
- name: checkout tkey repo
uses: actions/checkout@v3
with:
path: tkey
# with:
# path: tkey

- name: switch path
run: |
cd ./tkey
# - name: switch path
# run: |
# cd ./tkey

- name: Set up node
uses: actions/setup-node@v3
Expand All @@ -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`"
Expand All @@ -63,5 +63,4 @@ jobs:

- name: Running comp tests
run: |
cd ./backward-compatibility-tests
npm test
6 changes: 3 additions & 3 deletions karmaBaseConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/common-types/src/baseTypes/aggregateTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export interface IMetadata extends ISerializable {

nonce: number;

chainCode?: string;

getShareIndexesForPolynomial(polyID: PolynomialID): string[];
getLatestPublicPolynomial(): PublicPolynomial;
addTSSData(tssData: {
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
himanshuchawla009 marked this conversation as resolved.
Show resolved Hide resolved
"elliptic": "^6.5.4",
"json-stable-stringify": "^1.0.2"
},
Expand Down
51 changes: 45 additions & 6 deletions packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
toPrivKeyECC,
} from "@tkey-mpc/common-types";
import { generatePrivate } from "@toruslabs/eccrypto";
import { keccak256 } from "@toruslabs/torus.js";
import BN from "bn.js";
import stringify from "json-stable-stringify";

Expand All @@ -66,7 +67,6 @@ import {
lagrangeInterpolation,
} from "./lagrangeInterpolatePolynomial";
import Metadata from "./metadata";

// TODO: handle errors for get and set with retries

class ThresholdKey implements ITKey {
Expand Down Expand Up @@ -226,6 +226,19 @@ class ThresholdKey implements ITKey {
throw CoreError.metadataUndefined();
}

computeNonce(index: number) {
himanshuchawla009 marked this conversation as resolved.
Show resolved Hide resolved
// 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");
himanshuchawla009 marked this conversation as resolved.
Show resolved Hide resolved
}
return index && index > 0 ? new BN(keccak256(Buffer.from(`${index}${chainCode}`)).slice(2), "hex").umod(ecCurve.curve.n) : new BN(0);
himanshuchawla009 marked this conversation as resolved.
Show resolved Hide resolved
}

generateSalt() {
return generatePrivate().toString("hex");
himanshuchawla009 marked this conversation as resolved.
Show resolved Hide resolved
}

async initialize(params?: {
withShare?: ShareStore;
importKey?: BN;
Expand Down Expand Up @@ -300,7 +313,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();
himanshuchawla009 marked this conversation as resolved.
Show resolved Hide resolved
this.metadata.addTSSData({ tssTag: this.tssTag, tssNonce: 0, tssPolyCommits, factorPubs, factorEncs, chainCode });
}
return this.getKeyDetails();
}
Expand Down Expand Up @@ -385,7 +399,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);
Expand All @@ -407,6 +421,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();
Expand All @@ -416,6 +431,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...");
Expand All @@ -425,8 +445,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];
Expand All @@ -445,6 +463,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) {
himanshuchawla009 marked this conversation as resolved.
Show resolved Hide resolved
return { tssIndex, tssShare };
}
Expand All @@ -461,7 +487,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") })

Choose a reason for hiding this comment

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

cleanup this code, calculate "this.getTSSCommits()" once and use it , rather thn calling it everytime

.getPublic();
const dervicepubKeyPoint = pubKeyPoint.add(noncePub);
Copy link

Choose a reason for hiding this comment

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

typo derivedPubKeyPoint

return new Point(dervicepubKeyPoint.getX().toString("hex"), dervicepubKeyPoint.getY().toString("hex"));
}
return this.getTSSCommits()[0];
}

Expand Down Expand Up @@ -876,12 +912,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) {
Expand Down
14 changes: 12 additions & 2 deletions packages/core/src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class Metadata implements IMetadata {
};
};

// salt
chainCode?: string;

constructor(input: Point) {
this.tssPolyCommits = {};
this.tssNonces = {};
Expand All @@ -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[] = [];
Expand All @@ -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) {
Expand Down Expand Up @@ -186,15 +190,20 @@ class Metadata implements IMetadata {
tssNonce?: number;
tssPolyCommits?: Point[];
factorPubs?: Point[];
accountIndex?: number;
Copy link

Choose a reason for hiding this comment

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

this should be removed rite?

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) {
Copy link

Choose a reason for hiding this comment

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

@himanshuchawla009 , Should we throw when chainCode exist and we try to update the chainCode?
or just ignore the update

Choose a reason for hiding this comment

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

So chainCode should be once generated and saved , it should not be updated. But we shouldnt throw error as well, so error should be ignored.

this.chainCode = chainCode;
}
}

// appends shares and public polynomial to metadata.
Expand Down Expand Up @@ -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 }),
};
}
}
Expand Down
3 changes: 0 additions & 3 deletions packages/default/test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
});
}
Expand Down Expand Up @@ -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(
Expand Down
Loading
Loading