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 wallets #92

Closed
wants to merge 12 commits into from
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*

*.tgz
# todo: for local testing still tkey-mpc merge
# *.tgz
39 changes: 30 additions & 9 deletions src/mpcCoreKit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit {

private enableLogging = false;

private accountIndex;
ieow marked this conversation as resolved.
Show resolved Hide resolved

private ready = false;

constructor(options: Web3AuthOptions) {
Expand Down Expand Up @@ -141,6 +143,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
sessionId,
});
};
this.accountIndex = 0;
asyncConstructor();
}

Expand Down Expand Up @@ -482,6 +485,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
}
}

public async setTssWalletIndex(accountIndex: number) {
this.accountIndex = accountIndex;
await this.finalizeTkey(this.state.factorKey);
}

public getCurrentFactorKey(): IFactorKey {
this.checkReady();
if (!this.state.factorKey) throw new Error("factorKey not present");
Expand All @@ -499,7 +507,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit {

public getTssPublicKey(): TkeyPoint {
this.checkReady();
return this.tKey.getTSSPub();
// pass this optional account index;
return this.tKey.getTSSPub(this.accountIndex);
}

public async enableMFA(enableMFAParams: EnableMFAParams, recoveryFactor = true): Promise<string> {
Expand Down Expand Up @@ -607,6 +616,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
return Buffer.from(tssPubKey);
};

public getNonce = () => {
// call tkey with index and get nonce
return this.accountIndex ? this.tkey.computeNonce(this.accountIndex) : new BN(0);
};

public sign = async (msgHash: Buffer): Promise<{ v: number; r: Buffer; s: Buffer }> => {
// if (this.state.remoteClient) {
// return this.remoteSign(msgHash);
Expand All @@ -625,7 +639,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
});

if (!this.state.factorKey) throw new Error("factorKey not present");
const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey);
const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey, {
accountIndex: this.accountIndex,
threshold: 0,
});
const tssNonce = this.getTssNonce();

if (!tssPubKey || !torusNodeTSSEndpoints) {
Expand Down Expand Up @@ -687,9 +704,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
const serverIndex = participatingServerDKGIndexes[i];
serverCoeffs[serverIndex] = getDKLSCoeff(false, participatingServerDKGIndexes, tssShareIndex as number, serverIndex).toString("hex");
}

client.precompute(tss, { signatures, server_coeffs: serverCoeffs });

client.precompute(tss, { signatures, server_coeffs: serverCoeffs, nonce: scalarBNToBufferSEC1(this.getNonce()).toString("base64") });
await client.ready().catch((err) => {
client.cleanup(tss, { signatures, server_coeffs: serverCoeffs });
throw err;
Expand Down Expand Up @@ -763,7 +778,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
public getKeyDetails(): MPCKeyDetails {
this.checkReady();
const tkeyDetails = this.tKey.getKeyDetails();
const tssPubKey = this.state.tssPubKey ? this.tKey.getTSSPub() : undefined;
const tssPubKey = this.state.tssPubKey ? this.tKey.getTSSPub(this.accountIndex) : undefined;

const factors = this.tKey.metadata.factorPubs ? this.tKey.metadata.factorPubs[this.tKey.tssTag] : [];
const keyDetails: MPCKeyDetails = {
Expand Down Expand Up @@ -884,8 +899,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit {

private async finalizeTkey(factorKey: BN) {
// Read tss meta data.
const { tssIndex: tssShareIndex } = await this.tKey.getTSSShare(factorKey);
const tssPubKey = Point.fromTkeyPoint(this.tKey.getTSSPub()).toBufferSEC1(false);
const { tssIndex: tssShareIndex } = await this.tKey.getTSSShare(factorKey, {
accountIndex: this.accountIndex,
threshold: 0,
});
const tssPubKey = Point.fromTkeyPoint(this.tKey.getTSSPub(this.accountIndex)).toBufferSEC1(false);

this.updateState({ tssShareIndex, tssPubKey, factorKey });

Expand Down Expand Up @@ -939,7 +957,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
this.sessionManager.sessionId = sessionId;
const { oAuthKey, factorKey, userInfo, tssShareIndex, tssPubKey } = this.state;
if (!this.state.factorKey) throw new Error("factorKey not present");
const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey);
const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey, {
accountIndex: this.accountIndex,
threshold: 0,
});
if (!oAuthKey || !factorKey || !tssShare || !tssPubKey || !userInfo) {
throw new Error("User not logged in");
}
Expand Down
4 changes: 4 additions & 0 deletions tests/factors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const FactorManipulationTest = async (newInstance: () => Promise<Web3Auth

await t.test("should able to create factor", async function () {
const coreKitInstance = await newInstance();
coreKitInstance.setTssWalletIndex(1);
const firstFactor = coreKitInstance.getCurrentFactorKey();
// try delete hash factor factor
try {
Expand All @@ -63,6 +64,7 @@ export const FactorManipulationTest = async (newInstance: () => Promise<Web3Auth

// new instance
const instance2 = await newInstance();
instance2.setTssWalletIndex(1);
assert.strictEqual(instance2.getTssFactorPub().length, 3);

// try inputFactor ( set as active factor )
Expand All @@ -88,6 +90,7 @@ export const FactorManipulationTest = async (newInstance: () => Promise<Web3Auth

await t.test("enable MFA", async function () {
const instance = await newInstance();
instance.setTssWalletIndex(1);
const recoverFactor = await instance.enableMFA({});

if (testVariable.manualSync) {
Expand All @@ -99,6 +102,7 @@ export const FactorManipulationTest = async (newInstance: () => Promise<Web3Auth

// new instance
const instance2 = await newInstance();

let browserFactor;
if (testVariable.storage) {
browserFactor = await getWebBrowserFactor(instance2, testVariable.storage);
Expand Down
60 changes: 58 additions & 2 deletions tests/login.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ const variable: TestVariable[] = [
// { web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET, uxMode: UX_MODE.REDIRECT, manualSync: true, email: defaultTestEmail },
];

const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit) => {
const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) => {
const keyDetails = coreKitInstance.getKeyDetails();
assert.strictEqual(coreKitInstance.status, COREKIT_STATUS.LOGGED_IN);
assert.strictEqual(keyDetails.requiredFactors, 0);
const factorkey = coreKitInstance.getCurrentFactorKey();
await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex"));
await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex"), {
threshold: 0,
accountIndex,
});
};

variable.forEach((testVariable) => {
Expand Down Expand Up @@ -121,5 +124,58 @@ variable.forEach((testVariable) => {
assert.strictEqual(pubkey.x.toString("hex"), publicKeyPoint.x.toString("hex"));
assert.strictEqual(pubkey.y.toString("hex"), publicKeyPoint.y.toString("hex"));
});

await t.test("#Login and sign with different account/wallet index", async function () {
// mock login with random
const { idToken: idToken2, parsedToken: parsedToken2 } = await mockLogin();
await coreKitInstance.init({ handleRedirectResult: false });
await coreKitInstance.loginWithJWT({
verifier: "torus-test-health",
verifierId: parsedToken2.email,
idToken: idToken2,
});

const secp256k1 = new EC("secp256k1");
await coreKitInstance.setTssWalletIndex(0);

const msg = "hello world 1";
const msgBuffer = Buffer.from(msg);
const msgHash = keccak256(msgBuffer);
const signature1 = await coreKitInstance.sign(msgHash);

const pubkey1 = secp256k1.recoverPubKey(msgHash, signature1, signature1.v - 27);
const publicKeyPoint1 = coreKitInstance.getTssPublicKey();
assert.strictEqual(pubkey1.x.toString("hex"), publicKeyPoint1.x.toString("hex"));
assert.strictEqual(pubkey1.y.toString("hex"), publicKeyPoint1.y.toString("hex"));

await coreKitInstance.setTssWalletIndex(1);

const msg1 = "hello world 2";
const msgBuffer1 = Buffer.from(msg1);
const msgHash1 = keccak256(msgBuffer1);

const signature2 = await coreKitInstance.sign(msgHash1);

const pubkey2 = secp256k1.recoverPubKey(msgHash1, signature2, signature2.v - 27);
const publicKeyPoint2 = coreKitInstance.getTssPublicKey();
assert.strictEqual(pubkey2.x.toString("hex"), publicKeyPoint2.x.toString("hex"));
assert.strictEqual(pubkey2.y.toString("hex"), publicKeyPoint2.y.toString("hex"));

await checkLogin(coreKitInstance, 1);

await coreKitInstance.setTssWalletIndex(2);

const msg2 = "hello world 3";
const msgBuffer2 = Buffer.from(msg2);
const msgHash2 = keccak256(msgBuffer2);
const signature3 = await coreKitInstance.sign(msgHash2);

const pubkey3 = secp256k1.recoverPubKey(msgHash2, signature3, signature3.v - 27);
const publicKeyPoint3 = coreKitInstance.getTssPublicKey();
assert.strictEqual(pubkey3.x.toString("hex"), publicKeyPoint3.x.toString("hex"));
assert.strictEqual(pubkey3.y.toString("hex"), publicKeyPoint3.y.toString("hex"));

await checkLogin(coreKitInstance, 2);
});
});
});
11 changes: 2 additions & 9 deletions tests/securityQuestion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,7 @@ import { UX_MODE_TYPE } from "@toruslabs/customauth";
import * as TssLib from "@toruslabs/tss-lib-node";
import BN from "bn.js";

import {
BrowserStorage,
COREKIT_STATUS,
SupportedStorageType,
TssSecurityQuestion,
WEB3AUTH_NETWORK,
WEB3AUTH_NETWORK_TYPE,
Web3AuthMPCCoreKit,
} from "../src";
import { BrowserStorage, SupportedStorageType, TssSecurityQuestion, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src";
import { criticalResetAccount, mockLogin } from "./setup";

type TestVariable = {
Expand Down Expand Up @@ -44,6 +36,7 @@ export const TssSecurityQuestionsTest = async (newInstance: () => Promise<Web3Au
await t.test("should work", async function () {
// set security question
const instance = await newInstance();
instance.setTssWalletIndex(1);
const question = "test question";
const answer = "test answer";
const newQuestion = "new question";
Expand Down
18 changes: 17 additions & 1 deletion tests/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,23 @@ const privateKey = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCD7oLrcKae+jVZ
const jwtPrivateKey = `-----BEGIN PRIVATE KEY-----\n${privateKey}\n-----END PRIVATE KEY-----`;
const alg: Algorithm = "ES256";

export const mockLogin = async (email: string) => {
export const mockLogin = async (email?: string) => {
// if email is not passed generate a random email
function stringGen(len: number) {
let text = "";
const charset = "abcdefghijklmnopqrstuvwxyz0123456789";

for (let i = 0; i < len; i++) {
text += charset.charAt(Math.floor(Math.random() * charset.length));
}

return text;
}

if (!email) {
email = `${stringGen(10)}@${stringGen(5)}.${stringGen(3)}`;
}

const iat = Math.floor(Date.now() / 1000);
const payload = {
iss: "torus-key-test",
Expand Down
Binary file added tkey-mpc-core-9.0.3.tgz
Binary file not shown.
Loading